Skip to main content

loom-api-documentation

Document REST APIs with OpenAPI/Swagger specifications, endpoint references, authentication flows, error handling, and SDK guides.

Informations de source

Dépôt
cosmix/loom
Dernière activité de la source
29 août 2026 à 21:19
Langue détectée de SKILL.md
anglais
Étoiles
61
Forks
4

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
loom-api-documentation
description
Document REST APIs with OpenAPI/Swagger specifications, endpoint references, authentication flows, error handling, and SDK guides.
triggers
["api docs","openapi","swagger","endpoint documentation","rest api","api reference","sdk documentation","api specification","document api","api endpoints","request response examples","schema documentation","openapi 3.1","redoc","stoplight","postman collection","api explorer","interactive docs","api contract","api schema","swagger ui","authentication flows","rate limits","contract testing","spec-first"]
# API Documentation ## Overview Produce API docs developers can actually use: an accurate OpenAPI spec as the source of truth, plus reference/auth/error/versioning guides generated or kept in sync with it. Correctness and drift-prevention matter more than prose. ## What every API must document Auth · base URLs per environment · every endpoint + operation · request/response schemas · **all** response codes (incl. errors) · rate limits (with headers) · pagination · versioning/deprecation policy. ## Spec-first vs code-first (choose deliberately) | Approach | How | Drift risk | Use when | | -------- | --- | ---------- | -------- | | **Spec-first** | Hand-write OpenAPI, generate server stubs + clients + mocks | Runtime can diverge from spec unless validated | New APIs, contract negotiated across teams, mock-driven frontend | | **Code-first** | Annotate handlers; framework emits spec (FastAPI, springdoc, drf-spectacular, tsoa) | Spec stays close to code, but annotations can lie | Existing codebase, small team, code is the truth | Either way, **enforce the contract in CI** (lint + validate examples + breaking-change diff). Docs that aren't tested against the running API are fiction. ## OpenAPI 3.1 — what changed from 3.0 (get these right) - **Fully aligned with JSON Schema 2020-12.** A schema is now a valid JSON Schema; you can set `jsonSchemaDialect` and use `$schema` per-schema. - **`nullable: true` is GONE.** Use a type array: `type: [string, "null"]`. - **Type can be an array**: `type: [string, integer]`. - **`exclusiveMinimum`/`exclusiveMaximum` are numbers**, not booleans (draft-4 behavior removed). - **Top-level `webhooks`** describe events the API *sends* (see below). - **Examples split by object**: Schema Objects use JSON Schema's `examples` (an **array**); Media Type / Parameter Objects use `example` (singular) or `examples` (a **map of named Example Objects** with `summary`/`value`). Don't confuse the two. - `info.license.identifier` accepts an **SPDX** id (e.g., `MIT`) instead of a URL. - `$ref` may now sit alongside sibling keywords (e.g., `description`). ⚠ Tooling lag: Swagger UI / some generators still have partial 3.1 support. Verify your renderer and codegen handle 3.1 before committing to `type: [..., "null"]` everywhere. ## Documentation quality rules - Write for competent developers: skip patronizing basics; lead with a working example, then explain. - Keep schemas DRY with `$ref`; reuse `parameters`, `responses`, `securitySchemes` from `components`. - **Every operation needs a unique `operationId`** — it becomes the generated client's method name. Renaming it is a breaking change for SDK users. - Tag endpoints for navigation; realistic example data (not `foo`/`bar`); document rate limits with concrete numbers **and** the exact headers. - Validate every example against its schema (Redocly/Spectral catch this). ## Examples ### OpenAPI 3.1 spec (trimmed to the load-bearing shapes) ```yaml openapi: 3.1.0 info: title: User Management API version: 2.0.0 license: { name: MIT, identifier: MIT } # 3.1 SPDX identifier servers: - { url: https://api.example.com/v2, description: Production } - { url: https://api.staging.example.com/v2, description: Staging } security: - BearerAuth: [] tags: - { name: Users, description: User management } paths: /users: get: summary: List users operationId: listUsers # stable → SDK method name tags: [Users] parameters: - $ref: "#/components/parameters/LimitParam" - name: status in: query schema: { type: string, enum: [active, inactive, pending] } responses: "200": description: OK content: application/json: schema: { $ref: "#/components/schemas/UserListResponse" } examples: # media-type: MAP of named Example Objects page1: summary: First page value: data: [{ id: usr_123, email: john@example.com, status: active }] pagination: { limit: 20, next_cursor: "eyJpZCI6MTIzfQ", has_more: true } "401": { $ref: "#/components/responses/Unauthorized" } "429": { $ref: "#/components/responses/RateLimited" } post: summary: Create user operationId: createUser tags: [Users] parameters: - name: Idempotency-Key in: header schema: { type: string } requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/CreateUserRequest" } responses: "201": { description: Created, content: { application/json: { schema: { $ref: "#/components/schemas/User" } } } } "409": description: Email already exists content: application/json: schema: { $ref: "#/components/schemas/Problem" } webhooks: # 3.1: events the API SENDS userCreated: post: requestBody: content: application/json: schema: { $ref: "#/components/schemas/User" } responses: "200": { description: Receiver acknowledged } 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: { "users:read": Read users, "users:write": Manage users } parameters: LimitParam: name: limit in: query schema: { type: integer, minimum: 1, maximum: 100, default: 20 } schemas: User: type: object required: [id, email, status] properties: id: { type: string, example: usr_123 } email: { type: string, format: email } status: { type: string, enum: [active, inactive, pending] } deletedAt: { type: [string, "null"], format: date-time } # 3.1 nullable CreateUserRequest: type: object required: [email, name, password] properties: email: { type: string, format: email } name: { type: string, minLength: 2, maxLength: 100 } password: { type: string, format: password, minLength: 8 } UserListResponse: type: object properties: data: { type: array, items: { $ref: "#/components/schemas/User" } } pagination: type: object properties: limit: { type: integer } next_cursor: { type: [string, "null"] } has_more: { type: boolean } Problem: # RFC 9457 application/problem+json type: object properties: type: { type: string, format: uri } title: { type: string } status: { type: integer } detail: { type: string } errors: type: array items: type: object properties: field: { type: string } code: { type: string } message: { type: string } responses: Unauthorized: description: Authentication required content: application/json: schema: { $ref: "#/components/schemas/Problem" } RateLimited: description: Rate limit exceeded headers: X-RateLimit-Limit: { schema: { type: integer }, description: Requests per window } X-RateLimit-Remaining: { schema: { type: integer } } X-RateLimit-Reset: { schema: { type: integer }, description: Unix epoch when window resets } Retry-After: { schema: { type: integer }, description: Seconds to wait } content: application/json: schema: { $ref: "#/components/schemas/Problem" } ``` ### Endpoint reference (Markdown template) ````markdown ## Create User — `POST /users` Auth: Bearer token. Idempotent via `Idempotency-Key` header. **Body** | Field | Type | Req | Notes | | -------- | ------ | --- | ------------------------------------------------- | | email | string | yes | Valid email | | name | string | yes | 2–100 chars | | password | string | yes | ≥8 chars; upper+lower+digit+symbol | ```bash curl -X POST https://api.example.com/v2/users \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 9f1c...-once" \ -d '{"email":"jane@example.com","name":"Jane Smith","password":"SecureP@ss123"}' ``` **201 Created** → `{ "id": "usr_abc123", "email": "jane@example.com", "status": "pending" }` | Status | Code | Meaning | | ------ | ---------------- | ------------------------ | | 401 | UNAUTHORIZED | Missing/invalid token | | 409 | USER_EXISTS | Email already registered | | 422 | VALIDATION_ERROR | See `errors[]` per field | | 429 | RATE_LIMITED | Honor `Retry-After` | ```` ### Auth flows (document the full lifecycle, not just the header) ````markdown ## Bearer (JWT) `POST /auth/login` → `{ "accessToken": "...", "refreshToken": "...", "expiresIn": 3600 }` Send `Authorization: Bearer <accessToken>`. Access token 1h, refresh 30d; `POST /auth/refresh` to renew. ## API key (server-to-server) `X-API-Key: sk_live_...`. Never ship keys client-side; scope minimally; rotate ≤90 days; one key per environment. ```` ### Documenting errors, rate limits, versioning consistently Reference the RFC 9457 `Problem` schema for **every** error response; maintain one canonical error-code table: | Code | HTTP | Meaning | Client action | | ---- | ---- | ------- | ------------- | | UNAUTHORIZED | 401 | No/invalid token | Re-auth | | INSUFFICIENT_SCOPE | 403 | Token lacks scope | Request scopes | | VALIDATION_ERROR | 422 | Field validation failed | Inspect `errors[]` | | NOT_FOUND | 404 | Missing resource | Verify id | | ALREADY_EXISTS | 409 | Duplicate/conflict | Use unique key | | RATE_LIMITED | 429 | Throttled | Wait `Retry-After` | Rate limits: always document the window, the limit, and the `X-RateLimit-*` + `Retry-After` headers. Versioning: publish supported versions + sunset dates, classify breaking vs non-breaking, and give side-by-side migration examples plus `Deprecation`/`Sunset` response headers. ## Tooling | Job | Tool | Command | | --- | ---- | ------- | | Render (3-panel) | Redoc | `npx @redocly/cli build-docs openapi.yaml -o docs.html` | | Render (try-it) | Swagger UI | `docker run -p 80:8080 -e SWAGGER_JSON=/api/openapi.yaml -v $(pwd):/api swaggerapi/swagger-ui` | | Embed | Stoplight Elements | `<elements-api apiDescriptionUrl="./openapi.yaml" router="hash" />` | | Lint | Spectral / Redocly | `spectral lint openapi.yaml` · `npx @redocly/cli lint openapi.yaml` | | Bundle | Redocly | `npx @redocly/cli bundle openapi.yaml -o bundled.yaml` | | Client gen | OpenAPI Generator | `openapi-generator-cli generate -i openapi.yaml -g typescript-fetch -o ./client` | | Postman | openapi-to-postmanv2 | `openapi2postmanv2 -s openapi.yaml -o collection.json` | | Mock | Prism | `prism mock openapi.yaml` | | Contract test | Dredd / Schemathesis | `dredd openapi.yaml http://localhost:3000` · `schemathesis run openapi.yaml` | | Breaking-change diff | oasdiff | `oasdiff breaking old.yaml new.yaml` | ## Keeping docs in sync with code (the real problem) Docs rot the moment they're decoupled from the running service. Enforce sync mechanically: - **Runtime validation** — proxy requests/responses through the spec (`express-openapi-validator`, Prism proxy) in dev/staging; a mismatch fails the build. - **Contract tests in CI** — Dredd (example-driven) or Schemathesis (property-based fuzzing derived from the schema) run against the real API; Schemathesis catches undocumented 500s and schema violations you'd never write by hand. - **Breaking-change gate** — `oasdiff breaking` (or openapi-diff) on every PR blocks silent contract breaks. - **Lint gate** — Spectral ruleset enforces house style (descriptions present, `operationId` unique, examples valid, error responses documented). - **Single source** — generate SDKs and mocks from the spec so they can't disagree; never hand-maintain a second copy of the contract. ## Anti-patterns - Documenting only happy-path 200s — clients need the 4xx/5xx bodies and codes to handle failure. - Prose clients must parse (switching on `message` text). Give stable machine-readable `code`/`type`. - `example` vs `examples` mixups (schema=array, media-type=map) — renders empty or errors in tooling. - Reusing/renaming `operationId` — silently breaks generated SDKs. - Fake data (`foo`/`bar`) and fragment-only snippets — show complete, copy-pasteable, realistic requests. - Screenshots of JSON instead of copyable code blocks. ## Checklists **Spec quality — before publish:**
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub