OpenAPI Emission
Generate an OpenAPI 3.0 JSON spec alongside your TypeScript output. Your C# types and endpoints become a standards-compliant API spec — useful for documentation tools, API gateways, and external consumers.
Command
dotnet rivet --project path/to/Api.csproj --output ./generated --openapiThis produces everything the normal forward pipeline does (types, client, validators) plus an openapi.json file.
Security schemes
Add a security scheme to the spec with --security:
# Bearer token
dotnet rivet --project Api.csproj -o dir --openapi --security bearer
# Bearer JWT
dotnet rivet --project Api.csproj -o dir --openapi --security bearer:jwt
# Cookie-based
dotnet rivet --project Api.csproj -o dir --openapi --security cookie:sid
# API key in header
dotnet rivet --project Api.csproj -o dir --openapi --security apikey:header:X-Api-KeyPer-endpoint security
On contract endpoints, use .Anonymous() and .Secure(scheme) to control per-endpoint security:
public static readonly RouteDefinition<List<MemberDto>> List =
Define.Get<List<MemberDto>>("/api/members")
.Summary("List all team members")
.Anonymous(); // no auth required
public static readonly RouteDefinition<InviteMemberRequest, InviteMemberResponse> Invite =
Define.Post<InviteMemberRequest, InviteMemberResponse>("/api/members")
.Summary("Invite a new team member")
.Description("Creates a new member invitation and sends an email notification")
.Secure("admin"); // requires admin schemeThese are emitted as security: [] (anonymous) or security: [{ admin: [] }] on the corresponding OpenAPI operation.
What it produces
The generated openapi.json includes:
- Paths — one operation per endpoint, with parameters, request bodies, and response schemas
- Schemas — all C# types marked with
[RivetType]or referenced by endpoints, under#/components/schemas - Security schemes — if
--securityis specified - Summary / Description —
.Summary()emits to the operationsummaryfield,.Description()todescription - Property metadata —
[RivetDescription],[RivetConstraints],[RivetDefault],[RivetExample],[RivetReadOnly],[RivetWriteOnly]attributes are emitted on property schemas - Type descriptions —
[RivetDescription]on records emitsdescriptionon the schema object - Endpoint/content examples — request and response examples on the endpoint model emit to
requestBody.content[*]andresponses[*].content[*]
Type representation
- Generic types are monomorphised:
PagedResult<TaskDto>becomesPagedResult_TaskDtoin the schema, with anx-rivet-genericextension that allows the importer to reconstruct the generic template - Branded value objects (single-property records) are emitted as component schemas with an
x-rivet-brandextension (e.g.,Emailbecomes{ "type": "string", "x-rivet-brand": "Email" }), and references use$ref - File upload records with
IFormFileproperties producemultipart/form-dataschemas using$refto the component schema, withx-rivet-filemarkers on file properties - Enums are
type: stringwithenum: [...] - Nullable types use
nullable: true
The x-rivet-* extensions are ignored by non-Rivet consumers (valid OpenAPI 3.0). They enable lossless round-trips when the spec is imported back into Rivet.
Endpoint/content example emission
Rivet emits endpoint-level examples from either contract builder calls or controller example attributes.
- One unnamed inline example on a media type emits as singular
example. - Named examples, multiple examples, and ref-backed examples emit under
examples. - Ref-backed examples emit
$refentries that point at#/components/examples/{id}when Rivet has both the component id and resolved JSON payload. - If Rivet cannot safely emit a valid ref, it inlines the example content instead of producing a broken
$ref.
Example:
public static readonly RouteDefinition<CreateWidgetRequest, WidgetDto> Create =
Define.Post<CreateWidgetRequest, WidgetDto>("/api/widgets")
.RequestExampleJson("{\"name\":\"starter-widget\"}")
.Returns<ProblemDto>(422)
.ResponseExampleRef(
422,
"widget-validation-problem",
"{\"title\":\"Validation failed\"}",
name: "validationProblem");This feature covers request-body and response-body examples. Property-level examples still come from [RivetExample] on DTO properties and emit on schemas, not on operation content.
Viewing the spec
The generated openapi.json works with any OpenAPI 3.0 tool:
- Swagger Editor — paste or upload the JSON
- Redocly —
npx @redocly/cli preview-docs openapi.json - API gateways (Kong, AWS API Gateway, Azure APIM) — import directly
Consistency with import
The OpenAPI emitter and the OpenAPI importer use consistent type mappings. What the emitter outputs, the importer can consume — enabling a round-trip workflow where you emit a spec, hand it to another team, and they import it back.
The emitter annotates the spec with x-rivet-* vendor extensions so that brands, generic types, and file upload record names survive the round-trip without loss. See OpenAPI Round-Trips for details.
