
Openapi
- 130 installs
- 14 repo stars
- Updated March 2, 2026
- oakoss/agent-skills
Helps with ai & agent building tasks during AI-assisted development.
About
openapi is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- openapi
- AI & Agent Building
- AI-coding skill
Openapi by the numbers
- 130 all-time installs (skills.sh)
- +10 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #3,681 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/oakoss/agent-skills --skill openapiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 130 |
|---|---|
| repo stars | ★ 14 |
| Last updated | March 2, 2026 |
| Repository | oakoss/agent-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
OpenAPI
Overview
OpenAPI Specification (OAS) 3.1 is the industry standard for describing HTTP APIs. It defines a machine-readable contract covering endpoints, request/response schemas, authentication, and error formats. OpenAPI 3.1 is a strict superset of JSON Schema Draft 2020-12, enabling full JSON Schema compatibility for data validation and type generation.
When to use: Designing REST APIs, generating typed clients (TypeScript, Python, Go), producing interactive documentation, validating request/response payloads, contract-first API development, API gateway configuration.
When NOT to use: GraphQL APIs (use the GraphQL schema), gRPC services (use Protocol Buffers), WebSocket-only protocols, internal function calls that never cross a network boundary.
Quick Reference
| Pattern | Element | Key Points |
|---|---|---|
| Document root | openapi, info, paths | openapi: '3.1.0' required at top level |
| Path item | /resources/{id} | Curly braces for path parameters |
| Operation | get, post, put, delete, patch | Each operation needs operationId and responses |
| Parameters | `in: path\ | query\ |
| Request body | requestBody.content | Keyed by media type (application/json) |
| Response | responses.200.content | At least one response required per operation |
| Component ref | $ref: '#/components/schemas/Name' | Reuse schemas, parameters, responses |
| Schema types | `type: string\ | number\ |
| Composition | oneOf, anyOf, allOf | Model polymorphism and intersection types |
| Discriminator | discriminator.propertyName | Hint for code generators with oneOf/anyOf |
| Security | securitySchemes + top-level security | Bearer, API key, OAuth2, OpenID Connect |
| Tags | tags on operations | Group operations for documentation |
| Type generation | openapi-typescript | Zero-runtime TypeScript types from spec |
| Typed fetch | openapi-fetch | Type-safe HTTP client using generated types |
| React Query | openapi-react-query | Type-safe React Query hooks from spec |
| Schema-first | zod-openapi | Generate OpenAPI documents from Zod schemas |
Common Mistakes
| Mistake | Correct Pattern |
|---|---|
Using nullable: true in 3.1 | Use type: ["string", "null"] (3.0 syntax removed) |
Missing operationId on operations | Always set unique operationId for code generation |
Path parameter not in required | Path parameters are always required (required: true) |
| Inline schemas everywhere | Extract to components/schemas and use $ref |
allOf with conflicting required fields | Merge required arrays; allOf unions them |
| Discriminator without shared property | All schemas in oneOf/anyOf must include the discriminator property |
Empty description on responses | Every response needs a meaningful description |
Using type: object without properties | Always define properties or use additionalProperties |
Circular $ref chains | Break cycles with lazy resolution or restructure schemas |
| Mixing 3.0 and 3.1 syntax | Choose one version; 3.1 drops nullable, changes exclusiveMinimum to number |
Delegation
- API design review: Use
Taskagent to audit spec completeness and consistency - Type generation: Use
Exploreagent to find project-specific OpenAPI tooling config - Code review: Delegate to
code-revieweragent for generated client usage patterns
If the typescript-patterns skill is available, delegate advanced TypeScript typing questions to it.References
- Schema design: paths, operations, parameters, components, and $ref
- Data types: formats, composition, discriminators, and nullable
- Code generation: openapi-typescript, openapi-fetch, openapi-react-query, and Zod OpenAPI
- Documentation: Swagger UI, Redoc, and API docs best practices
Code Generation
openapi-typescript
Generates zero-runtime TypeScript types from OpenAPI 3.0/3.1 schemas.
Installation
npm i -D openapi-typescript typescriptGenerate Types
From a local file:
npx openapi-typescript ./path/to/api.yaml -o ./src/lib/api/v1.d.tsFrom a remote URL:
npx openapi-typescript https://api.example.com/openapi.json -o ./src/lib/api/v1.d.tsGenerated Type Structure
The output creates a paths interface keyed by path and method:
import type { paths } from './api/v1';
type ListUsersResponse =
paths['/users']['get']['responses']['200']['content']['application/json'];
type CreateUserBody =
paths['/users']['post']['requestBody']['content']['application/json'];
type GetUserParams = paths['/users/{userId}']['get']['parameters']['path'];Script Integration
Add to package.json for consistent regeneration:
{
"scripts": {
"generate:api": "openapi-typescript ./openapi.yaml -o ./src/lib/api/schema.d.ts"
}
}openapi-fetch
Type-safe HTTP client that uses types generated by openapi-typescript. Zero runtime overhead beyond native fetch.
Installation
npm i openapi-fetch
npm i -D openapi-typescript typescriptClient Setup
import createClient from 'openapi-fetch';
import type { paths } from './api/v1';
const client = createClient<paths>({ baseUrl: 'https://api.example.com/v1/' });GET Requests
const { data, error } = await client.GET('/users/{userId}', {
params: {
path: { userId: '123' },
},
});
if (error) {
console.error(error.code, error.message);
return;
}
console.log(data.name);GET with Query Parameters
const { data, error } = await client.GET('/users', {
params: {
query: { page: 1, limit: 20, role: 'admin' },
},
});POST Requests
const { data, error } = await client.POST('/users', {
body: {
name: 'Jane Doe',
email: 'jane@example.com',
role: 'member',
},
});PUT Requests
const { data, error } = await client.PUT('/users/{userId}', {
params: {
path: { userId: '123' },
},
body: {
name: 'Jane Smith',
email: 'jane.smith@example.com',
},
});DELETE Requests
const { data, error } = await client.DELETE('/users/{userId}', {
params: {
path: { userId: '123' },
},
});Middleware
Add authentication or logging with middleware:
const client = createClient<paths>({
baseUrl: 'https://api.example.com/v1/',
});
client.use({
async onRequest({ request }) {
const token = getAccessToken();
request.headers.set('Authorization', `Bearer ${token}`);
return request;
},
async onResponse({ request, response }) {
if (response.status === 401) {
await refreshToken();
}
return response;
},
async onError({ error }) {
return new Error('Fetch failed', { cause: error });
},
});Error Handling Pattern
The data and error fields are mutually exclusive based on status code:
const { data, error, response } = await client.GET('/users/{userId}', {
params: { path: { userId: '123' } },
});
if (error) {
switch (response.status) {
case 404:
console.error('User not found');
break;
case 422:
console.error('Validation errors:', error.errors);
break;
default:
console.error('Unexpected error:', error.message);
}
return;
}
console.log(data.name);Zod OpenAPI
Generate OpenAPI 3.1 documents from Zod schemas. Keeps validation and documentation in sync.
Installation
npm i zod-openapi zodDefine Schemas with Metadata
Use .meta() to attach OpenAPI metadata to Zod schemas:
import * as z from 'zod';
import { createDocument } from 'zod-openapi';
const UserId = z.string().uuid().meta({
description: 'Unique user identifier',
example: '550e8400-e29b-41d4-a716-446655440000',
id: 'UserId',
});
const UserName = z.string().min(1).max(255).meta({
description: 'User display name',
example: 'Jane Doe',
});
const UserEmail = z.string().email().meta({
description: 'User email address',
example: 'jane@example.com',
});
const UserRole = z.enum(['admin', 'member', 'viewer']).meta({
description: 'User role within the organization',
id: 'UserRole',
});The id field in .meta() auto-registers the schema as a reusable component in the output document.
Create a Document
const document = createDocument({
openapi: '3.1.0',
info: {
title: 'Users API',
version: '1.0.0',
},
paths: {
'/users/{userId}': {
get: {
operationId: 'getUser',
requestParams: {
path: z.object({ userId: UserId }),
},
responses: {
'200': {
description: 'User details',
content: {
'application/json': {
schema: z.object({
id: UserId,
name: UserName,
email: UserEmail,
role: UserRole,
}),
},
},
},
'404': {
description: 'User not found',
content: {
'application/json': {
schema: z.object({
code: z.string(),
message: z.string(),
}),
},
},
},
},
},
},
},
});Generate Standalone Schemas
Use createSchema when you need just the schema and components without a full document:
import { createSchema } from 'zod-openapi';
const User = z.object({
id: UserId,
name: UserName,
email: UserEmail,
role: UserRole,
});
const { schema, components } = createSchema(User);The schema output is a valid OpenAPI Schema Object. The components object contains any schemas registered via id in .meta().
Request Body with Zod
const CreateUserRequest = z.object({
name: UserName,
email: UserEmail,
role: UserRole.optional().default('member'),
});
const document = createDocument({
openapi: '3.1.0',
info: { title: 'Users API', version: '1.0.0' },
paths: {
'/users': {
post: {
operationId: 'createUser',
requestBody: {
required: true,
content: {
'application/json': { schema: CreateUserRequest },
},
},
responses: {
'201': {
description: 'User created',
content: {
'application/json': {
schema: z.object({
id: UserId,
name: UserName,
email: UserEmail,
role: UserRole,
}),
},
},
},
},
},
},
},
});Writing the Document to YAML
import { stringify } from 'yaml';
const yamlOutput = stringify(document);Output the YAML to a file for use with other OpenAPI tools (documentation generators, API gateways, client generators).
openapi-react-query
Type-safe React Query hooks generated from openapi-fetch:
npm i openapi-react-query openapi-fetch
npm i -D openapi-typescript typescriptimport createFetchClient from 'openapi-fetch';
import createClient from 'openapi-react-query';
import type { paths } from './api/v1';
const fetchClient = createFetchClient<paths>({
baseUrl: 'https://api.example.com/v1/',
});
const $api = createClient(fetchClient);
function UserProfile({ userId }: { userId: string }) {
const { data, error, isPending } = $api.useQuery('get', '/users/{userId}', {
params: { path: { userId } },
});
if (isPending) return 'Loading...';
if (error) return `Error: ${error.message}`;
return data.name;
}Requires @tanstack/react-query as a peer dependency.
Data Types
Primitive Types
OpenAPI 3.1 supports JSON Schema Draft 2020-12 types:
type: string
type: number
type: integer
type: boolean
type: array
type: object
type: 'null'In 3.1, type can be an array to express union types:
type: ['string', 'null']String Formats
properties:
id:
type: string
format: uuid
email:
type: string
format: email
website:
type: string
format: uri
created:
type: string
format: date-time
birthday:
type: string
format: date
duration:
type: string
format: duration
ip:
type: string
format: ipv4
password:
type: string
format: passwordNumber Constraints
properties:
age:
type: integer
minimum: 0
maximum: 150
price:
type: number
minimum: 0
exclusiveMinimum: 0
multipleOf: 0.01
quantity:
type: integer
minimum: 1
maximum: 1000In OpenAPI 3.1, exclusiveMinimum and exclusiveMaximum are numbers (not booleans as in 3.0):
properties:
score:
type: number
exclusiveMinimum: 0
exclusiveMaximum: 100String Constraints
properties:
username:
type: string
minLength: 3
maxLength: 32
pattern: '^[a-zA-Z0-9_]+$'
slug:
type: string
pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'Enums and Constants
properties:
status:
type: string
enum: [active, inactive, suspended]
version:
type: string
const: '1.0'Arrays
properties:
tags:
type: array
items:
type: string
minItems: 1
maxItems: 10
uniqueItems: true
matrix:
type: array
items:
type: array
items:
type: number
minItems: 3
maxItems: 3
coordinates:
type: array
prefixItems:
- type: number
- type: number
items: false
minItems: 2
maxItems: 2Objects
properties:
metadata:
type: object
properties:
key:
type: string
required: [key]
additionalProperties: false
tags:
type: object
additionalProperties:
type: string
minProperties: 1
maxProperties: 20
config:
type: object
propertyNames:
pattern: '^[a-z][a-zA-Z0-9]*$'
additionalProperties:
type: stringNullable Fields (3.1)
OpenAPI 3.1 removed nullable: true. Use type arrays instead:
properties:
middleName:
type: ['string', 'null']
deletedAt:
type: ['string', 'null']
format: date-time
bio:
oneOf:
- type: string
maxLength: 500
- type: 'null'Composition: allOf
Combine schemas (intersection). All subschemas must validate:
components:
schemas:
BaseEntity:
type: object
properties:
id:
type: string
format: uuid
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
required: [id, createdAt, updatedAt]
User:
allOf:
- $ref: '#/components/schemas/BaseEntity'
- type: object
properties:
name:
type: string
email:
type: string
format: email
required: [name, email]Composition: oneOf
Exactly one subschema must validate (exclusive union):
components:
schemas:
PaymentMethod:
oneOf:
- $ref: '#/components/schemas/CreditCard'
- $ref: '#/components/schemas/BankTransfer'
- $ref: '#/components/schemas/DigitalWallet'
CreditCard:
type: object
properties:
type:
type: string
const: credit_card
cardNumber:
type: string
expiryMonth:
type: integer
expiryYear:
type: integer
required: [type, cardNumber, expiryMonth, expiryYear]
BankTransfer:
type: object
properties:
type:
type: string
const: bank_transfer
accountNumber:
type: string
routingNumber:
type: string
required: [type, accountNumber, routingNumber]
DigitalWallet:
type: object
properties:
type:
type: string
const: digital_wallet
provider:
type: string
enum: [apple_pay, google_pay]
token:
type: string
required: [type, provider, token]Composition: anyOf
At least one subschema must validate (inclusive union). Use when the value can match one or more schemas:
components:
schemas:
SearchFilter:
anyOf:
- type: object
properties:
name:
type: string
required: [name]
- type: object
properties:
email:
type: string
format: email
required: [email]Discriminator
Hints for code generators to select the correct schema branch. Only valid with oneOf, anyOf, or allOf:
components:
schemas:
Event:
oneOf:
- $ref: '#/components/schemas/UserCreatedEvent'
- $ref: '#/components/schemas/OrderPlacedEvent'
- $ref: '#/components/schemas/PaymentProcessedEvent'
discriminator:
propertyName: eventType
mapping:
user.created: '#/components/schemas/UserCreatedEvent'
order.placed: '#/components/schemas/OrderPlacedEvent'
payment.processed: '#/components/schemas/PaymentProcessedEvent'
UserCreatedEvent:
type: object
properties:
eventType:
type: string
userId:
type: string
required: [eventType, userId]
OrderPlacedEvent:
type: object
properties:
eventType:
type: string
orderId:
type: string
total:
type: number
required: [eventType, orderId, total]
PaymentProcessedEvent:
type: object
properties:
eventType:
type: string
paymentId:
type: string
amount:
type: number
required: [eventType, paymentId, amount]Every schema in the oneOf/anyOf must include the discriminator property. Without explicit mapping, schema names are used as discriminator values.
readOnly and writeOnly
Control which properties appear in requests vs responses:
components:
schemas:
User:
type: object
properties:
id:
type: string
format: uuid
readOnly: true
password:
type: string
format: password
writeOnly: true
name:
type: string
required: [id, name]readOnly: true— included in responses, excluded from requestswriteOnly: true— included in requests, excluded from responses
Default Values
properties:
role:
type: string
enum: [admin, member, viewer]
default: member
isActive:
type: boolean
default: true
pageSize:
type: integer
default: 20
minimum: 1
maximum: 100Documentation
Swagger UI
Interactive API documentation that lets consumers explore and test endpoints directly in the browser.
Docker Setup
docker run -p 8080:8080 -e SWAGGER_JSON=/app/openapi.yaml -v ./openapi.yaml:/app/openapi.yaml swaggerapi/swagger-uiExpress Integration
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import spec from './openapi.json';
const app = express();
app.use(
'/api-docs',
swaggerUi.serve,
swaggerUi.setup(spec, {
customCss: '.swagger-ui .topbar { display: none }',
customSiteTitle: 'My API Documentation',
}),
);HTML Standalone
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>API Docs</title>
<link
rel="stylesheet"
href="https://unpkg.com/swagger-ui-dist/swagger-ui.css"
/>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script>
SwaggerUIBundle({
url: '/openapi.yaml',
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset,
],
layout: 'StandaloneLayout',
});
</script>
</body>
</html>Redoc
Clean, three-panel documentation with excellent navigation and search.
HTML Standalone
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>API Reference</title>
</head>
<body>
<redoc spec-url="/openapi.yaml"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
</body>
</html>Redoc Configuration
<redoc
spec-url="/openapi.yaml"
hide-download-button
required-props-first
sort-props-alphabetically
expand-responses="200,201"
path-in-middle-panel
hide-hostname
native-scrollbars
></redoc>CLI Build
Generate a zero-dependency static HTML file:
npx @redocly/cli build-docs openapi.yaml -o docs/index.htmlRedocly CLI
Linting, bundling, and previewing OpenAPI specs:
npx @redocly/cli lint openapi.yaml
npx @redocly/cli bundle openapi.yaml -o dist/openapi.yaml
npx @redocly/cli preview-docs openapi.yamlRedocly Configuration
Create a redocly.yaml for project-wide rules:
extends:
- recommended
rules:
operation-operationId: error
operation-summary: warn
no-path-trailing-slash: error
no-ambiguous-paths: error
tag-description: warn
info-contact: warn
no-unused-components: warnDocumentation Best Practices
Descriptions
Write concise, actionable descriptions on every element:
paths:
/users:
get:
summary: List users
description: >
Returns a paginated list of users. Results are sorted by creation date
(newest first). Use query parameters to filter by role or status.
parameters:
- name: role
in: query
description: Filter users by their assigned role
schema:
$ref: '#/components/schemas/UserRole'Examples
Provide realistic examples at multiple levels:
components:
schemas:
User:
type: object
properties:
id:
type: string
format: uuid
example: 550e8400-e29b-41d4-a716-446655440000
name:
type: string
example: Jane Doe
email:
type: string
format: email
example: jane@example.com
required: [id, name, email]
paths:
/users/{userId}:
get:
responses:
'200':
description: User details
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
admin:
summary: Admin user
value:
id: 550e8400-e29b-41d4-a716-446655440000
name: Jane Doe
email: jane@example.com
role: admin
member:
summary: Regular member
value:
id: 7c9e6679-7425-40de-944b-e07fc1f90ae7
name: John Smith
email: john@example.com
role: memberTags and Grouping
Organize operations into logical groups:
tags:
- name: Authentication
description: Login, logout, and token management
- name: Users
description: User CRUD operations and profile management
- name: Organizations
description: Organization management and membership
paths:
/auth/login:
post:
tags: [Authentication]
operationId: login
/users:
get:
tags: [Users]
operationId: listUsers
/organizations:
get:
tags: [Organizations]
operationId: listOrganizationsError Documentation
Document error responses consistently across all operations:
components:
responses:
BadRequest:
description: Invalid request parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: BAD_REQUEST
message: Invalid request body
Unauthorized:
description: Missing or invalid authentication
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: UNAUTHORIZED
message: Authentication required
Forbidden:
description: Insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: FORBIDDEN
message: You do not have permission to access this resource
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: NOT_FOUND
message: User not found
RateLimited:
description: Too many requests
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: RATE_LIMITED
message: Rate limit exceededMulti-File Specs
Split large specs across files and bundle before publishing:
api/
openapi.yaml # Root document
paths/
users.yaml # /users and /users/{userId}
auth.yaml # /auth/*
schemas/
user.yaml
error.yaml
parameters/
pagination.yamlReference external files:
paths:
/users:
$ref: 'paths/users.yaml#/users'
components:
schemas:
User:
$ref: 'schemas/user.yaml#/User'Bundle into a single file for distribution:
npx @redocly/cli bundle openapi.yaml -o dist/openapi.yamlWebhooks (3.1)
OpenAPI 3.1 added top-level webhooks for documenting callback events:
webhooks:
userCreated:
post:
summary: User created event
operationId: onUserCreated
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
event:
type: string
const: user.created
data:
$ref: '#/components/schemas/User'
timestamp:
type: string
format: date-time
required: [event, data, timestamp]
responses:
'200':
description: Webhook receivedSchema Design
Document Structure
Every OpenAPI 3.1 document requires three top-level fields:
openapi: '3.1.0'
info:
title: My API
version: 1.0.0
description: A sample API
contact:
name: API Support
email: support@example.com
license:
name: MIT
paths: {}Optional top-level fields: servers, components, security, tags, externalDocs, webhooks.
Servers
Define base URLs for different environments:
servers:
- url: https://api.example.com/v1
description: Production
- url: https://staging-api.example.com/v1
description: Staging
- url: http://localhost:3000/v1
description: Local developmentServer URLs support variables:
servers:
- url: https://{environment}.example.com/v1
variables:
environment:
default: api
enum: [api, staging, sandbox]Paths and Operations
Each path defines operations (HTTP methods):
paths:
/users:
get:
operationId: listUsers
summary: List all users
tags: [users]
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/LimitParam'
responses:
'200':
description: Paginated list of users
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
post:
operationId: createUser
summary: Create a new user
tags: [users]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'422':
$ref: '#/components/responses/ValidationError'
/users/{userId}:
get:
operationId: getUser
summary: Get a user by ID
tags: [users]
parameters:
- $ref: '#/components/parameters/UserIdParam'
responses:
'200':
description: User details
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'Parameters
Four parameter locations: path, query, header, cookie.
components:
parameters:
UserIdParam:
name: userId
in: path
required: true
description: Unique user identifier
schema:
type: string
format: uuid
PageParam:
name: page
in: query
required: false
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
ApiVersionHeader:
name: X-API-Version
in: header
required: false
schema:
type: string
default: '2024-01'Path parameters must always have required: true. Query parameters with array values use style and explode:
parameters:
- name: tags
in: query
schema:
type: array
items:
type: string
style: form
explode: trueRequest Bodies
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
examples:
basic:
summary: Basic user
value:
name: Jane Doe
email: jane@example.com
multipart/form-data:
schema:
type: object
properties:
avatar:
type: string
format: binary
name:
type: string
required: [name]Responses
Every operation needs at least one response. Define reusable responses in components:
components:
responses:
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ValidationError:
description: Validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'Response headers:
responses:
'200':
description: Success
headers:
X-Request-Id:
schema:
type: string
format: uuid
X-Rate-Limit-Remaining:
schema:
type: integerComponents and $ref
Extract reusable elements into components:
components:
schemas:
User:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
minLength: 1
maxLength: 255
email:
type: string
format: email
role:
$ref: '#/components/schemas/UserRole'
createdAt:
type: string
format: date-time
required: [id, name, email, role, createdAt]
CreateUserRequest:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 255
email:
type: string
format: email
role:
$ref: '#/components/schemas/UserRole'
required: [name, email]
UserRole:
type: string
enum: [admin, member, viewer]
UserList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
pagination:
$ref: '#/components/schemas/Pagination'
required: [data, pagination]
Pagination:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
required: [page, limit, total]
Error:
type: object
properties:
code:
type: string
message:
type: string
required: [code, message]Security Schemes
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read:users: Read user data
write:users: Modify user data
security:
- BearerAuth: []Per-operation security overrides the global setting:
paths:
/public/health:
get:
security: []
responses:
'200':
description: Health checkTags
Group operations for documentation and code generation:
tags:
- name: users
description: User management
- name: auth
description: Authentication and authorizationoperationId Best Practices
Use verb-noun format for clear code generation output. Generated TypeScript functions map directly to operationId values:
paths:
/users:
get:
operationId: listUsers
post:
operationId: createUser
/users/{userId}:
get:
operationId: getUser
put:
operationId: updateUser
delete:
operationId: deleteUser