Generate API code, types, validators, mock servers, and client SDKs from a single OpenAPI 3.1 specification. Use whenever building or modifying an HTTP API endpoint. The OpenAPI doc is source of truth - drift between doc and code is a contract violation caught by tests. Triggers on requests involving REST endpoints, API design, or client/server contracts.
Resources
2Install
npx skillscat add miltonadina/devops/openapi-first Install via the SkillsCat registry.
OpenAPI First
The API contract is the source of truth. Code derives from it, not the other
way around.
Tradeoff: Adds an upfront OpenAPI authoring step. Worth it: free types,
free validators, free client SDKs, free mocks, and contract testing comes for
free.
When to invoke
- New API endpoint requested
- Existing endpoint being modified (request/response shape changes)
- Client SDK needed for an existing API
- Migration from undocumented API to documented
Workflow
- Write or update the OpenAPI 3.1 spec at
openapi/<service>.yml. - Generate types for both server and client.
- Generate validators so runtime requests are checked against the schema.
- Implement the handler to satisfy the spec (the test is "the
schema-validator passes against real requests/responses"). - Generate the mock server for frontend development.
- Add a contract test that exercises every operation against the spec.
Recommended tooling (TypeScript)
openapi-typescript— type generationzod-openapior@asteasolutions/zod-to-openapi— write schemas in
Zod, derive OpenAPI from them@hono/zod-openapiorfastify-openapi-glue— server framework
integrationorvalor@kubb/swagger-client— typed client SDK generation@stoplight/prism— mock serverschemathesisordredd— contract testing
For Python (FastAPI)
FastAPI generates OpenAPI from typed handlers — the spec is derived from code.
This works in reverse to "OpenAPI first." If you have an existing FastAPI app,
treat its /openapi.json output as authoritative and treat the docs export as
the canonical spec for client generation.
For Rust
utoipa— Rust code annotations generate OpenAPIpaperclip— alternative annotation-based generatorprogenitor— generate Rust client from OpenAPI
Quality gates
- The OpenAPI spec MUST validate against the OpenAPI 3.1 schema.
spectral lint openapi/<service>.ymlMUST pass with the default ruleset
(extend with.spectral.yamlfor project rules).- Generated types MUST be checked into the repo and re-generated by CI on
schema changes. Drift = build failure. - Contract tests MUST run on every PR.
- Breaking changes MUST be detected by
oasdiffand require a major version bump.
Anti-patterns
Hand-writing types after the schema: defeats the purpose. Always generate.
Schema-after: writing the handler and then describing it in OpenAPI. Don't.
The schema is the design artifact.
Optional everywhere: if a field is always required in practice, mark it
required. Schema laxity becomes runtime errors.
Missing error responses: every operation should document 4xx and 5xx
responses with Problem Details (RFC 9457) bodies.
No versioning strategy: pick header-based (Accept: application/vnd.api+json; version=2) or path-based (/v2/) and stick to it.
Worked example
openapi/auth.yml:
openapi: 3.1.0
info:
title: Auth Service
version: 1.0.0
paths:
/auth/reset:
post:
operationId: requestPasswordReset
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ResetRequest'
responses:
'200':
description: Reset link sent
'422':
description: Invalid email
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
'429':
description: Rate limited
components:
schemas:
ResetRequest:
type: object
required: [email]
properties:
email: { type: string, format: email, maxLength: 320 }
Problem:
type: object
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
detail: { type: string }Generated code provides:
- Server handler type signature
- Client SDK method
client.requestPasswordReset({ email }) - Mock server endpoint
- Contract test for valid + invalid inputs
This skill is working when: every API endpoint in the project is described
in OpenAPI, every type is generated (not hand-written), and contract tests run
on every PR. Track in governance/telemetry/openapi-coverage.jsonl.