Skip to main content Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/diegosouzapw/awesome-omni-skill --skill api-design命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... 同仓库更多 Skills Token-efficient tracking for AI orchestration. CLI-first for status updates (~50 tokens), agent fallback for complex ops (~1KB). Use when: updating task status, querying blockers, creating progress files, validating phases.
AshAi extension guidelines for integrating AI capabilities with Ash Framework. Use when implementing vectorization/embeddings, exposing Ash actions as LLM tools, creating prompt-backed actions, or setting up MCP servers. Covers semantic search, LangChain integration, and structured outputs.
This skill should be used when solving hard questions, complex architectural problems, or debugging issues that benefit from GPT-5 Pro or GPT-5.1 thinking models with large file context. Use when standard Claude analysis needs deeper reasoning or extended context windows.
name api-design description Design REST and GraphQL APIs. Covers endpoint naming, versioning, OpenAPI 3.1 specs, pagination, error handling, and auth patterns.
API Design
Quick Start
Just describe your domain:
design an API for an e-commerce platform with products, orders, and customers
You'll get a complete endpoint design and OpenAPI snippet like:
paths:
/v1/products:
get:
summary: List products
parameters:
- $ref: '#/components/parameters/PageLimit'
- $ref: '#/components/parameters/PageCursor'
responses:
'200':
description: Paginated product list
content:
application/json:
schema:
$ref: '#/components/schemas/ProductListResponse'
/v1/products/{id}:
get:
summary: Get product by ID
responses:
'200':
description: Product detail
'404':
$ref: '#/components/responses/NotFound'
What to include in your request:
Domain or system name (e-commerce, billing, identity)
Key resources (users, products, orders)
Relationships (orders belong to users, orders have line items)
Consumer context (mobile app, internal service, public API)
Existing constraints (auth system, versioning requirements)
Triggers
Trigger Example design an API for"design an API for a task management system" create endpoints for"create endpoints for user authentication" OpenAPI spec for"OpenAPI spec for the billing service" GraphQL schema for"GraphQL schema for a content management domain" review api"review this API for problems" add endpoints for"add endpoints for order fulfillment" design REST API"design REST API for the notification service"
Key Terms
Term Definition REST Representational State Transfer — stateless, resource-oriented HTTP API style GraphQL Query language for APIs with a single endpoint and client-driven data fetching OpenAPI Standard specification format for describing REST APIs (current version: 3.1) Endpoint A URL path + HTTP method combination that handles a specific operation Resource A noun representing an entity in your domain (user, order, product) Schema Formal definition of the shape and constraints of request/response data Idempotency An operation that produces the same result no matter how many times it's called HATEOAS Hypermedia As The Engine Of Application State — embedding navigable links in responses Pagination Strategy for returning large datasets in chunks (offset-based or cursor-based) Rate Limiting Restricting how often a client can call an endpoint within a time window
Quick Reference
Task Approach Key Consideration New API Start with resource identification Model the domain, not the UI Versioning URL path /v1/ for simplicity Commit to support policy before launch Pagination Cursor-based for large/live data Offset breaks on concurrent writes Auth Bearer token (JWT) as default Scope to least privilege Error handling { error: { type, message, subcode } } envelopeMachine-readable codes, human-readable messages GraphQL vs REST REST for CRUD, GraphQL for flexible queries Consider client diversity and caching needs
Process Overview
Your API Requirements
|
v
+-----------------------------------------------------+
| Phase 1: REQUIREMENTS |
| * Identify resources and relationships |
| * Determine consumers (mobile, web, service-to-service) |
| * Define auth model and access control needs |
| * Enumerate constraints (rate limits, SLAs, quotas) |
+-----------------------------------------------------+
|
v
+-----------------------------------------------------+
| Phase 2: DESIGN |
| * Define URL structure and resource hierarchy |
| * Map HTTP methods to CRUD operations |
| * Design request/response schemas |
| * Choose auth mechanism and scoping |
+-----------------------------------------------------+
|
v
+-----------------------------------------------------+
| Phase 3: SPECIFY |
| * Generate OpenAPI 3.1 spec (or GraphQL SDL) |
| * Define error codes and Problem Details format |
| * Document pagination strategy and parameters |
| * Add examples for every endpoint |
+-----------------------------------------------------+
|
v
+-----------------------------------------------------+
| Phase 4: VALIDATE |
| * Run verification checklist |
| * Assess breaking change risk |
| * Review auth coverage |
| * Confirm documentation completeness |
+-----------------------------------------------------+
|
v
Production-Ready API Specification
Commands
Command When to Use Action design api for {domain}Starting fresh Full endpoint design + OpenAPI spec add endpoints for {resource}Extending existing API New resource endpoints openapi spec for {api}Formalizing existing design Complete OpenAPI 3.1 document graphql schema for {domain}GraphQL API Type definitions + queries + mutations review apiAuditing existing API Checklist audit + recommendations
Workflow: Start with design api → formalize with openapi spec → extend with add endpoints → audit with review api
Core Principles
Principle WHY Implementation Resource-oriented design Resources are stable; operations on them are predictable Nouns in URLs, verbs in HTTP methods Consistent naming Reduces cognitive load for consumers Plural nouns, kebab-case paths, camelCase fields Explicit versioning Allows evolution without breaking clients Version in URL path or header, committed from day one Defensive schemas Fail fast on bad input; never trust caller data Required fields, format constraints, max lengths
Anti-Patterns
Avoid Why Instead Verbs in URLs (/getUser, /createOrder) Conflates HTTP method semantics GET /users/{id}, POST /ordersInconsistent pluralization Forces clients to memorize per-resource conventions Always plural: /users, /orders, /products No versioning on day one First breaking change forces emergency migration Add /v1/ from the start Generic error responses ({"error": "failed"}) Client can't distinguish or act on error { error: { type, message, subcode } } with typed codesBreaking changes without deprecation Breaks deployed clients silently Additive changes only; Sunset header for removals Nesting resources more than 2 levels deep URLs become unmaintainable and coupling increases /orders/{id}/items yes; /users/{id}/orders/{id}/items/{id} noFLOAT for monetary values in responses Floating-point rounding corrupts financial data Return money as integer cents or string decimal Exposing internal IDs or database row numbers Leaks implementation, complicates migration Use opaque IDs (UUIDs or slugs)
Verification Checklist
After designing an API:
All resource URLs use plural nouns
No verbs in URL paths
Nesting depth is 2 levels maximum
URL paths use kebab-case for multi-word segments
HTTP methods match semantics (GET=read, POST=create, PUT=replace, PATCH=partial, DELETE=remove)
PUT and DELETE are idempotent
Status codes are appropriate (201 for creation, 204 for no-content DELETE, 409 for conflict)
Version is in URL path or header, documented from day one
All endpoints with state mutation require auth
Error responses use { error: { type, message, subcode } } envelope
Validation errors include field-level detail
Pagination included for all collection endpoints
Pagination response includes meta.total, meta.cursor, or links.next
Money/currency fields use integer cents or string decimal (never float)
Dates use ISO 8601 in UTC (2025-10-31T14:30:00Z)
Content-Type is application/json on all JSON endpoints
Rate limiting headers documented (X-RateLimit-Limit, X-RateLimit-Remaining)
OpenAPI spec validates without errors
Every endpoint has at least one request/response example
Breaking changes assessed against existing consumers
See api-design-checklist.md for the full pre-launch review checklist.
See openapi-templates.md for concrete OpenAPI 3.1 spec templates.
See scalar-api-docs.md for interactive API documentation setup (Go, Python, TypeScript, Rust).
Deep Dive: REST Endpoint Design
Resource Naming
Rule Good Bad Plural nouns /users, /orders/user, /orderkebab-case /line-items, /tax-rates/lineItems, /taxRatesNo verbs POST /ordersPOST /createOrderOpaque IDs /users/usr_abc123/users/42
URL Structure
/v1/{resource} # collection
/v1/{resource}/{id} # single resource
/v1/{resource}/{id}/{child} # sub-resource (max 2 levels)
Examples:
GET /v1/orders # list orders
POST /v1/orders # create order
GET /v1/orders/{id} # get order
PUT /v1/orders/{id} # replace order
PATCH /v1/orders/{id} # partial update
DELETE /v1/orders/{id} # delete order
GET /v1/orders/{id}/items # list items for order
POST /v1/orders/{id}/items # add item to order
HTTP Method Mapping
Method Semantics Idempotent Body GET Read, no side effects Yes No POST Create, trigger action No Yes PUT Replace entire resource Yes Yes PATCH Partial update No* Yes DELETE Remove resource Yes No
*PATCH can be made idempotent with conditional requests (If-Match)
Status Code Reference
Deep Dive: Response Format
Envelope Structure
Use a consistent envelope for all responses:
{
"data" : { ... } ,
"meta" : {
"requestId" : "req_abc123" ,
"timestamp" : "2025-10-31T14:30:00Z"
} ,
"links" : {
"self" : "/v1/orders/ord_xyz" ,
"next" : "/v1/orders?cursor=eyJpZCI6MTAwfQ"
} ,
"errors" : [ ... ]
}
data — the primary payload (object for single, array for collection)
meta — pagination cursors, request IDs, timestamps
links — HATEOAS navigation (self, next, prev, related actions)
errors — only present on error responses (4xx/5xx)
HATEOAS: Links and Actions
Use the links object for both navigation and available actions on the resource. Each key is a link relation type :
{
"data" :
Deep Dive: Versioning Strategies
Strategy Comparison
Strategy Example Pros Cons URL path /v1/ordersVisible, cacheable, easy to test Pollutes URL, not REST-pure Request header Accept-Version: 2Clean URLs, REST-pure Harder to test, requires header tooling Content negotiation Accept: application/vnd.api.v2+jsonStandards-compliant Verbose, limited browser/tool support Query parameter /orders?version=2Easy to test Cache-unfriendly, easy to forget
Recommendation
Default: URL path versioning.
Easiest to understand, document, and test
Works natively with all HTTP clients and proxies
Every environment can hit a specific version directly
Use header versioning only when you have multiple clients with very different needs and want a single URL namespace.
Version Lifecycle
v1 (stable) ──────────────────────────────────► active
v2 (preview) ────────► stable ─────────────────► active
v1 (sunset) Sunset header added ──────► deprecated ──► removed
Timeline example:
v1 launch : /v1/ is stable, no deprecation
v2 launch : Announce v2, keep v1 running
v1 sunset : Add Sunset: Sat, 31 Dec 2026 23:59:59 GMT header to v1 responses
v1 removal : 6–12 months after Sunset header, remove v1
Backward-Compatible Changes (No Version Bump Needed)
Adding optional request fields
Adding new response fields
Adding new endpoints
Adding new enum values (if clients handle unknown values)
Relaxing validation (e.g., increasing max length)
Breaking Changes (Require Version Bump)
Removing or renaming fields
Changing field types
Deep Dive: Pagination
Offset-Based vs Cursor-Based
Factor Offset Cursor Implementation Simple (LIMIT/OFFSET) Moderate (encode last-seen ID) Performance on large datasets Degrades (full table scan) Consistent (index seek) Handles concurrent writes Skips/duplicates items Stable position Supports jump to page N Yes No Best for Small datasets, admin UIs Large/live datasets, feeds
Offset Pagination Response
{
"data" : [ ... ] ,
"meta" : {
"total" : 1842 ,
"page" : 3 ,
"perPage" : 20 ,
"totalPages" : 93
} ,
"links" : {
"self" : "/v1/orders?page=3&perPage=20" ,
"prev" : "/v1/orders?page=2&perPage=20" ,
"next" :
Deep Dive: Error Handling
Error Response Format
Standard error envelope:
{
"error" : {
"type" : "BAD_REQUEST" ,
"message" : "Invalid email address format" ,
"subcode" : 12001
}
}
Field Description error.typeMachine-readable error category (SCREAMING_SNAKE_CASE) error.messageShort, human-readable description of the error error.subcodeNumeric code for programmatic handling and documentation lookup
Validation errors add a fields array:
{
"error" : {
"type" : "VALIDATION_FAILED" ,
"message" : "One or more fields failed validation" ,
"subcode" : 10001 ,
"fields" : [
{ "field" :
Deep Dive: Authentication and Authorization
Auth Mechanism Comparison
Mechanism Best For Complexity Stateless API Key Server-to-server, simple integrations Low Yes Bearer JWT User-facing APIs, short-lived tokens Medium Yes OAuth 2.0 + PKCE User-delegated access, third-party integrations High Yes Session cookies Traditional web apps, SSR Low No
Bearer Token (JWT) Pattern
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
JWT payload convention:
{
"sub" : "usr_abc123" ,
"iss" : "https://auth.example.com" ,
"aud" : "https://api.example.com" ,
"exp" : 1730386200 ,
"iat" : 1730382600 ,
"scope" : "orders:read orders:write"
}
API Key Pattern
X-API-Key: sk_live_abc123xyz
Prefix keys with environment (sk_live_, sk_test_) for instant recognition
Hash keys at rest; never store plaintext
Issue per-integration, not per-user
Support key rotation without downtime (accept both old and new during transition)
OAuth 2.0 Flows
Deep Dive: OpenAPI 3.1 Specification
Skeleton Template
openapi: 3.1 .0
info:
title: My Service API
version: 1.0 .0
description: |
Brief description of the API's purpose and audience.
contact:
name: Platform Team
email: platform@example.com
license:
name: MIT
servers:
- url: https://api.example.com/v1
description: Production
- url: https://api-staging.example.com/v1
description: Staging
security:
- bearerAuth: []
paths:
/resources:
get:
summary: List resources
operationId: listResources
tags: [Resources ]
parameters:
- $ref: '#/components/parameters/Limit'
- $ref:
[ , , ]
Deep Dive: GraphQL Schema Design
Type Definitions
scalar DateTime
scalar Decimal
type User {
id : ID!
email : String!
createdAt : DateTime!
orders( first : Int, after : String) : OrderConnection!
}
type Order {
id : ID!
status : OrderStatus!
total : Decimal!
currency : String!
lineItems : [ LineItem! ] !
createdAt : DateTime!
}
type LineItem {
id : ID!
product : Product!
Int
Decimal
OrderStatus
PENDING
CONFIRMED
SHIPPED
DELIVERED
CANCELLED
Deep Dive: Breaking Change Management
What Counts as Breaking
Change Breaking? Notes Add optional request field No Clients ignore unknown fields Add response field No Clients ignore unknown fields Remove request field Yes Existing clients may send it Remove response field Yes Existing clients may read it Rename field Yes Equivalent to remove + add Change field type Yes Parsing will fail Tighten validation Yes Previously valid requests rejected Loosen validation No More permissive Remove endpoint Yes 404 where clients expect 200 Change auth requirement Yes Auth failures for existing clients Add required request field Yes Existing requests missing the field Add new enum value Usually no* Depends on client handling unknown values
*Clients should be designed to handle unknown enum values gracefully.
Additive-Only Evolution
Design for additive-only changes within a major version:
Add new optional fields to requests
Add new fields to responses
Add new endpoints
Add new optional query parameters
Add new enum values (with consumer guidance on handling unknowns)
Deprecation Process
Step 1: Mark deprecated in OpenAPI spec
/v1/orders/{id}/cancel:
post:
deprecated: true
description: "Deprecated: Use PATCH /v1/orders/{id} with status=cancelled instead."
Step 2: Add Sunset header to responses
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/docs/migrations/v1-to-v2>; rel="deprecation"
Extension Points
Framework-Specific Patterns: Express middleware, FastAPI dependency injection, Go net/http routing conventions
API Gateway Integration: Kong, AWS API Gateway, Apigee — rate limiting, auth delegation, routing
Contract Testing: Pact for consumer-driven contract tests; validate against OpenAPI spec with dredd
SDK Generation: openapi-generator for client SDKs from OpenAPI spec; graphql-code-generator for TypeScript types
Spec Validation Automation: spectral rulesets in CI, redocly lint for doc quality gates
API Mocking: prism for mock servers from OpenAPI spec; enables parallel frontend/backend development
Interactive Documentation: Scalar for modern, themeable API reference UI — see references/scalar-api-docs.md
200 OK Successful GET, PUT, PATCH 201 Created Successful POST creating a resource 204 No Content Successful DELETE, or PUT/PATCH with no body 400 Bad Request Malformed request, validation failure 401 Unauthorized Missing or invalid authentication 403 Forbidden Authenticated but not authorized 404 Not Found Resource does not exist 409 Conflict Duplicate create, optimistic lock failure 422 Unprocessable Entity Semantically invalid (business rule violation) 429 Too Many Requests Rate limit exceeded 500 Internal Server Error Unexpected server failure 503 Service Unavailable Temporary outage, maintenance
Sub-Resource Patterns Keep sub-resources to actions that only make sense in context of the parent:
# Good: items only exist within an order
GET /v1/orders/{id}/items
POST /v1/orders/{id}/items
# Prefer flat resources when entities stand alone
GET /v1/items/{id} # better than /v1/orders/{oid}/items/{iid}
For actions that don't map cleanly to CRUD, use a verb suffix as a last resort:
POST /v1/orders/{id}/cancel
POST /v1/orders/{id}/fulfill
POST /v1/users/{id}/verify-email
{
"id"
:
"ord_xyz"
,
"status"
:
"pending"
,
"total"
:
1099
}
,
"links"
:
{
"self"
:
{
"href"
:
"/v1/orders/ord_xyz"
}
,
"cancel"
:
{
"href"
:
"/v1/orders/ord_xyz/cancel"
,
"method"
:
"POST"
}
,
"items"
:
{
"href"
:
"/v1/orders/ord_xyz/items"
}
,
"payment"
:
{
"href"
:
"/v1/orders/ord_xyz/pay"
,
"method"
:
"POST"
}
}
}
Actions are state-dependent — cancel only appears when the order is cancellable
Include method when the action is not a GET (avoids client guessing)
Use IANA-registered relation types where they exist (self, next, prev, collection)
Use descriptive custom relation types for domain actions (cancel, approve, payment)
Do NOT use a separate actions array — this is Siren format, not widely adopted. Standard links with method hints covers the same use case with less complexity
Field Naming Convention Convention When Example camelCase JSON APIs (default) createdAt, lineItemssnake_case Python/Go backends matching language convention created_at, line_items
Pick one and apply it everywhere. Document it in your OpenAPI spec's x-naming-convention extension.
Null Handling
Omit optional fields that have no value rather than returning null where possible
When null is semantically meaningful (explicitly unset vs absent), include it with documentation
Never return null for arrays — return []
Date Format "createdAt": "2025-10-31T14:30:00Z" # correct
"createdAt": "10/31/2025 2:30 PM" # wrong — ambiguous and locale-dependent
"createdAt": 1730382600 # avoid — requires client-side conversion
Monetary Values {
"amount" : 1099 ,
"currency" : "USD" ,
"amountFormatted" : "$10.99"
}
Store and transmit as integer cents (or smallest currency unit)
Include currency code with every monetary field
Optionally include a pre-formatted display string for convenience
Removing endpoints
Changing HTTP methods
Tightening validation
Changing authentication requirements "/v1/orders?page=4&perPage=20"
,
"first"
:
"/v1/orders?page=1&perPage=20"
,
"last"
:
"/v1/orders?page=93&perPage=20"
}
}
Cursor Pagination Response {
"data" : [ ... ] ,
"meta" : {
"hasNext" : true ,
"hasPrev" : true ,
"cursor" : {
"next" : "eyJpZCI6MTAwLCJjcmVhdGVkQXQiOiIyMDI1LTEwLTMxIn0=" ,
"prev" : "eyJpZCI6ODEsImNyZWF0ZWRBdCI6IjIwMjUtMTAtMzAifQ=="
}
}
}
GET /v1/orders?limit=20&after=eyJpZCI6MTAwfQ==
Cursor Implementation Pattern Encode the sort key(s) and last-seen ID in the cursor:
{ "id" : 100 , "createdAt" : "2025-10-31" }
Base64-encode this JSON — opaque to the client, but deterministic on the server.
Pagination Parameters Parameter Offset Cursor pagePage number (1-indexed) — perPage / limitItems per page Items per page after— Cursor for next page before— Cursor for prev page
Always enforce a maximum limit (e.g., 100) server-side regardless of what the client requests.
"quantity"
,
"code"
:
"INVALID_RANGE"
,
"message"
:
"Must be between 1 and 999"
}
,
{
"field"
:
"productId"
,
"code"
:
"NOT_FOUND"
,
"message"
:
"Product prod_zzz does not exist"
}
]
}
}
Request and Trace IDs Every response (success and error) must include correlation headers:
X-Request-Id: req_abc123 # Server-generated if client omits
X-Trace-Id: trace_def456 # Distributed tracing correlation
Retry-After: 60 # Seconds until retry (429, 503)
X-Request-Id: If the client sends one, echo it back. Otherwise, generate a UUID server-side. Log it with every request.
X-Trace-Id: Propagated through all downstream service calls for distributed tracing.
Do NOT put trace IDs in the error body. Headers are the canonical location — they're present on all responses (not just errors), are accessible to proxies/load balancers, and avoid coupling error schemas to tracing infrastructure. Clients needing to report an error to support should reference the X-Request-Id header value.
Error Code Registry Define typed error codes as constants in your API:
VALIDATION_FAILED 422 One or more fields are invalid 10001
RESOURCE_NOT_FOUND 404 The requested resource does not exist 10002
DUPLICATE_RESOURCE 409 A resource with this identifier exists 10003
INSUFFICIENT_FUNDS 422 Account balance is insufficient 10004
RATE_LIMIT_EXCEEDED 429 Too many requests; retry after X seconds 10005
UNAUTHORIZED 401 Authentication credentials invalid 10006
FORBIDDEN 403 Caller lacks permission for this action 10007
Document the full registry in your OpenAPI spec under x-error-codes.
HTTP Status Decision Tree Is the request malformed JSON? → 400 Bad Request
Do the fields fail validation? → 422 Unprocessable Entity
Is authentication missing or invalid? → 401 Unauthorized
Is the user authenticated but denied? → 403 Forbidden
Does the resource not exist? → 404 Not Found
Does a conflict exist (duplicate)? → 409 Conflict
Did a business rule fail? → 422 Unprocessable Entity
Is the server broken? → 500 Internal Server Error
Is the service temporarily unavailable? → 503 Service Unavailable
RFC 9457 Compatibility The error format above is intentionally simpler than RFC 9457 (Problem Details). If your API must comply with RFC 9457 (e.g., for interoperability with standards-mandating clients), use:
{
"type" : "https://api.example.com/errors/validation-failed" ,
"title" : "Validation Failed" ,
"status" : 422 ,
"detail" : "One or more fields failed validation." ,
"instance" : "/v1/orders/ord_xyz"
}
Set Content-Type: application/problem+json for RFC 9457 responses.
Flow When Authorization Code + PKCE Web/mobile apps on behalf of a user Client Credentials Service-to-service (no user context) Device Code Devices without browsers (CLI tools, smart TVs)
Scoping Define scopes as {resource}:{action} pairs:
orders:read Read orders
orders:write Create and update orders
orders:delete Delete orders
users:read Read user profiles
admin:full All access (restrict heavily)
Request minimum scopes. Validate scopes server-side on every request.
Rate Limiting Headers Always return rate limit state in responses:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1730383200
'#/components/parameters/After'
responses:
'200':
description:
Paginated
resource
list
content:
application/json:
schema:
$ref:
'#/components/schemas/ResourceListResponse'
'401':
$ref:
'#/components/responses/Unauthorized'
components:
securitySchemes:
bearerAuth:
type:
http
scheme:
bearer
bearerFormat:
JWT
apiKey:
type:
apiKey
in:
header
name:
X-API-Key
parameters:
Limit:
name:
limit
in:
query
schema:
type:
integer
minimum:
1
maximum:
100
default:
20
After:
name:
after
in:
query
schema:
type:
string
description:
Cursor
from
previous
response
for
next
page
responses:
Unauthorized:
description:
Authentication
credentials
missing
or
invalid
content:
application/json:
schema:
$ref:
'#/components/schemas/ProblemDetails'
NotFound:
description:
Resource
not
found
content:
application/json:
schema:
$ref:
'#/components/schemas/ProblemDetails'
schemas:
ProblemDetails:
type:
object
required:
type
title
status
properties:
type:
type:
string
format:
uri
title:
type:
string
status:
type:
integer
detail:
type:
string
instance:
type:
string
requestId:
type:
string
Reusable Schema Patterns ResourceListResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Resource'
meta:
$ref: '#/components/schemas/PaginationMeta'
links:
$ref: '#/components/schemas/PaginationLinks'
PaginationMeta:
type: object
properties:
hasNext:
type: boolean
hasPrev:
type: boolean
PaginationLinks:
type: object
properties:
self:
type: string
format: uri
next:
type: string
format: uri
prev:
type: string
format: uri
$ref Strategy
All reusable schemas in components/schemas
All reusable parameters in components/parameters
All reusable responses in components/responses
Never inline schema objects in paths — always $ref
Validation Tooling
spectral — OpenAPI linting with configurable rulesets
redocly — Spec validation + doc generation
swagger-cli validate — Basic structural validation
quantity
:
!
unitPrice
:
!
}
enum
{
}
Query, Mutation, Subscription Patterns type Query {
order( id : ID! ) : Order
orders( first : Int, after : String, filter : OrderFilter) : OrderConnection!
me : User
}
type Mutation {
createOrder( input : CreateOrderInput! ) : CreateOrderPayload!
cancelOrder( id : ID! ) : CancelOrderPayload!
}
type Subscription {
orderStatusChanged( orderId : ID! ) : Order!
}
Input Types input CreateOrderInput {
lineItems : [ LineItemInput! ] !
shippingAddressId : ID!
couponCode : String
}
input LineItemInput {
productId : ID!
quantity : Int!
}
Relay-Style Pagination (Connection Pattern) type OrderConnection {
edges : [ OrderEdge! ] !
pageInfo : PageInfo!
}
type OrderEdge {
cursor : String!
node : Order!
}
type PageInfo {
hasNextPage : Boolean!
hasPreviousPage : Boolean!
startCursor : String
endCursor : String
}
Error Handling: Errors Array vs Union Types Errors array (GraphQL default):
{
"data" : { "createOrder" : null } ,
"errors" : [ { "message" : "Product not found" , "path" : [ "createOrder" ] } ]
}
Union result types (recommended for mutations):
union CreateOrderResult = Order | ValidationError | NotFoundError
type Mutation {
createOrder( input : CreateOrderInput! ) : CreateOrderResult!
}
This approach makes errors first-class, typed, and queryable by clients.
Complexity and Depth Limiting Prevent abuse by enforcing query complexity limits:
Max depth : 7–10 levels (reject deeply nested queries)
Max complexity : Assign cost to each field; reject queries over budget
Introspection : Disable in production for public APIs
Libraries: graphql-depth-limit, graphql-query-complexity
Email registered API consumers
Post in developer changelog
Add in-response warning in meta.warnings array
Step 4: Enforce removal timeline
Minimum 6 months from Sunset header to removal for external APIs
Minimum 2 sprints for internal service-to-service APIs
Migration Guide Template ## Migrating from v1 to v2: Orders
### What changed
- `GET /v1/orders` response: `items` renamed to `lineItems`
- `POST /v1/orders` now requires `shippingAddressId`
- Error format changed from `{"error": "..."}` to `{ error: { type, message, subcode } }`
### Migration steps
1. Update `items` → `lineItems` in your order parsing code
2. Add `shippingAddressId` to order creation requests
3. Update error handling to read `type` and `detail` from responses
### Timeline
- v1 sunset: 2026-12-31
- v1 removal: 2027-03-31