{"id":48434257,"url":"https://github.com/maxanstey-meridian/rivet","last_synced_at":"2026-06-13T02:08:46.030Z","repository":{"id":345296104,"uuid":"1185283540","full_name":"maxanstey-meridian/rivet","owner":"maxanstey-meridian","description":"Your C# is the contract. Roslyn-derived OpenAPI 3.1 from ASP.NET endpoints or contract-first definitions — typed TS clients via the OpenAPI ecosystem","archived":false,"fork":false,"pushed_at":"2026-06-12T11:55:12.000Z","size":7662,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T12:07:00.857Z","etag":null,"topics":["api-client","aspnetcore","branded-types","code-generation","codegen","csharp","developer-tools","dotnet","full-stack","roslyn","runtime-validation","sealed-records","type-safety","typesafe","typescript","zod"],"latest_commit_sha":null,"homepage":"https://maxanstey-meridian.github.io/rivet/guides/tutorial","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxanstey-meridian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-18T12:28:37.000Z","updated_at":"2026-06-12T11:55:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/maxanstey-meridian/rivet","commit_stats":null,"previous_names":["maxanstey-meridian/rivet"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/maxanstey-meridian/rivet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxanstey-meridian%2Frivet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxanstey-meridian%2Frivet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxanstey-meridian%2Frivet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxanstey-meridian%2Frivet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxanstey-meridian","download_url":"https://codeload.github.com/maxanstey-meridian/rivet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxanstey-meridian%2Frivet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34269407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","aspnetcore","branded-types","code-generation","codegen","csharp","developer-tools","dotnet","full-stack","roslyn","runtime-validation","sealed-records","type-safety","typesafe","typescript","zod"],"created_at":"2026-04-06T12:02:58.766Z","updated_at":"2026-06-13T02:08:46.022Z","avatar_url":"https://github.com/maxanstey-meridian.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003eRivet\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.nuget.org/packages/Rivet.Attributes\"\u003e\u003cimg src=\"https://img.shields.io/nuget/v/Rivet.Attributes?label=Rivet.Attributes\" alt=\"NuGet\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.nuget.org/packages/dotnet-rivet\"\u003e\u003cimg src=\"https://img.shields.io/nuget/v/dotnet-rivet?label=dotnet-rivet\" alt=\"NuGet\" /\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue\" alt=\"License\" /\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n**Your C# is the contract.** Rivet reads your compiled C# with Roslyn and emits an\nOpenAPI 3.1 spec — no runtime reflection, no attributes-on-everything, no drift\nbetween the code and the spec. The OpenAPI ecosystem does the rest: TypeScript\ntypes, a typed fetch client, Zod schemas, rendered docs.\n\n[oRPC](https://orpc.unnoq.com) gives you this when your server is TypeScript.\nRivet gives you the same DX when your server is .NET.\n\n```bash\ndotnet add package Rivet.Attributes\ndotnet tool install --global dotnet-rivet\n```\n\n## Two ways in\n\n### Already have an ASP.NET API? Annotate it.\n\nMark the endpoints you want surfaced — the operation is derived from the real\ntransport shape (routes, params, bodies, response types):\n\n```csharp\n[ApiController]\n[Route(\"api/tasks\")]\npublic sealed class TasksController : ControllerBase\n{\n    [RivetEndpoint]\n    [HttpGet(\"{id:guid}\")]\n    [ProducesResponseType(typeof(TaskDetailDto), StatusCodes.Status200OK)]\n    [ProducesResponseType(typeof(NotFoundDto), StatusCodes.Status404NotFound)]\n    public async Task\u003cIActionResult\u003e Get(Guid id, CancellationToken ct) { ... }\n}\n```\n\nThat becomes `GET /api/tasks/{id}` with a typed `200` and `404` — route\nconstraints normalised, params classified, multipart and form bodies handled.\n\n### Starting fresh? Write the contract first.\n\nA contract is plain C#: routes, inputs, outputs, and error responses in one\nplace, as data:\n\n```csharp\n[RivetContract]\npublic static class MembersContract\n{\n    public static readonly RouteDefinition\u003cPagedResult\u003cMemberDto\u003e\u003e List =\n        Define.Get\u003cPagedResult\u003cMemberDto\u003e\u003e(\"/api/members\");\n\n    public static readonly RouteDefinition\u003cInviteMemberRequest, InviteMemberResponse\u003e Invite =\n        Define.Post\u003cInviteMemberRequest, InviteMemberResponse\u003e(\"/api/members\")\n            .Status(201)\n            .Returns\u003cValidationErrorDto\u003e(422, \"Validation failed\")\n            .Secure(\"admin\");\n}\n```\n\nHandlers execute the contract, so the compiler enforces that your implementation\nmatches the declaration — input type, output type, and (at runtime, on the\ntyped-results path) status codes:\n\n```csharp\n[HttpPost]\npublic async Task\u003cIActionResult\u003e Invite([FromBody] InviteMemberRequest request, CancellationToken ct)\n    =\u003e (await MembersContract.Invite.Invoke(request, async req =\u003e\n    {\n        // req is InviteMemberRequest; must return InviteMemberResponse — compiler-enforced\n        return new InviteMemberResponse(Guid.NewGuid());\n    })).ToActionResult();\n```\n\nEither way — annotated endpoints, contracts, or a mix — the spec comes out the same.\n\n## Generate\n\n```bash\ndotnet rivet --project path/to/Api.csproj --output ./generated\n```\n\nWrites `./generated/openapi.json`, derived from the compiled C# via the Roslyn\nsemantic model. Value-object brands, generics, nullability, validation\nattributes, polymorphic hierarchies (`oneOf` + discriminator), dictionary key\ntypes, headers, descriptions, and examples all flow into the spec.\n\n## Consume\n\nThe spec plugs straight into the OpenAPI TypeScript ecosystem:\n\n```bash\nnpx openapi-typescript ./generated/openapi.json -o ./src/api/schema.d.ts\nnpm install openapi-fetch\n```\n\n```ts\nimport createClient from \"openapi-fetch\";\nimport type { paths } from \"./api/schema\";\n\nconst api = createClient\u003cpaths\u003e({ baseUrl: \"https://api.example.com\" });\n\n// Path, params, body, and per-status responses all inferred.\nconst { data, error } = await api.GET(\"/api/tasks/{id}\", {\n  params: { path: { id: taskId } },\n});\n\nif (error) {\n  // narrowed to NotFoundDto for the declared 404\n  console.error(error.message);\n}\n```\n\nDocs via any OpenAPI renderer; runtime validators via\n[openapi-zod-client](https://github.com/astahmer/openapi-zod-client) if you want them.\n\n## Also in the box\n\n- [Contract coverage checking](https://maxanstey-meridian.github.io/rivet/guides/contract-coverage) — `--check` verifies every contract field has an implementation on the declared route and method\n- [OpenAPI import](https://maxanstey-meridian.github.io/rivet/guides/openapi-import) — one-shot onboarding for existing APIs: generate C# contracts from a spec, then the C# is the source of truth\n- [File endpoints](https://maxanstey-meridian.github.io/rivet/guides/file-uploads), headers as contract concepts, minimal-API hosts, [round-trippable specs](https://maxanstey-meridian.github.io/rivet/guides/openapi-round-trips)\n- Stable `RIVnnnn` [diagnostic IDs](https://maxanstey-meridian.github.io/rivet/reference/diagnostics) on every warning — grep or baseline by ID\n- A TypeScript-first sibling, [rivet-ts](https://github.com/maxanstey-meridian/rivet-ts) — same pipeline, contracts authored as TS types, Hono runtime\n\n## Documentation\n\n[Getting Started](https://maxanstey-meridian.github.io/rivet/getting-started) ·\n[Contracts](https://maxanstey-meridian.github.io/rivet/guides/contracts) ·\n[CLI Reference](https://maxanstey-meridian.github.io/rivet/reference/cli) ·\n[Type Mapping](https://maxanstey-meridian.github.io/rivet/reference/type-mapping) ·\n[Runtime Validation](https://maxanstey-meridian.github.io/rivet/guides/runtime-validation)\n(the precise scope of what is and isn't enforced at runtime)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxanstey-meridian%2Frivet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxanstey-meridian%2Frivet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxanstey-meridian%2Frivet/lists"}