api-design-first
API Design First
Acknowledgement: Shared by Peter Bamuhigire, techguypeter.com, +256 784 464178.
Design APIs as contracts before code. This skill produces the OpenAPI 3.1 contract and its companion auth / error / idempotency / observability artifacts that downstream frontend, mobile, SDK, security, and reliability skills depend on.
Use When
- Designing a new HTTP API (REST or GraphQL decision open), or adding endpoints to an existing API.
- Normalising an existing API against the house contract (envelope, error model, versioning, rate limits).
- Producing the OpenAPI contract that SDK, frontend, mobile, contract-testing, and security skills will consume.
- Choosing an auth method and writing the auth/role matrix for a new service.
- Defining idempotency keys and observability notes handed to
reliability-engineeringandobservability-monitoring.
Do Not Use When
- The task is purely client-side consumption of a third-party API (load the relevant SDK or integration skill).
- The task is full threat modelling — load
vibe-security-skill; this skill only records the auth model. - GraphQL-specific hardening is needed — load
graphql-security.
Required Inputs
- Context map and critical-flow table from
system-architecture-design. - Access-pattern list from
database-design-engineering. - Consumers, trust boundaries, and latency budget for each endpoint.
- Tenancy model (single-tenant, shared schema, schema-per-tenant) so
tenant_idpropagation can be proven.
Workflow
- Read this
SKILL.md, then load only the references needed for the task (for exampleopenapi-workflow.mdfor a greenfield design;auth-and-security.mdfor an auth choice;rest-conventions.mdfor URL / status-code review). - Apply the six-step design workflow before writing any code.
- Produce the OpenAPI contract in the template format from
skill-composition-standards/references/openapi-contract.md. - Record the auth model, error model, idempotency map, and observability notes alongside the spec.
- Run the implementation checklist before merging.
Quality Standards
- Spec is the source of truth; code follows the spec, never the reverse.
- Every endpoint has documented auth, error codes, rate limits, pagination where relevant, and observability notes.
- Tenant scope is derived from the auth token, never from a request body or query string.
- Breaking changes require a new major version; existing versions are frozen except for bug fixes.
- British English, no emojis, language-tagged code fences.
Anti-Patterns
- Writing code first and "generating" the spec afterwards — the spec loses its role as contract.
- Accepting
tenant_idfrom the request body — enables cross-tenant data leaks. - Returning 403 for wrong-tenant lookups — leaks existence; return 404.
- Wildcard
Access-Control-Allow-Origin: *with credentials — browsers ignore, auth breaks, security hole opens. - Storing API keys in plaintext — a database leak becomes an immediate credential leak.
- Mutating an existing version's response schema — every client with hard-coded parsers breaks.
Outputs
- OpenAPI 3.1 contract covering every endpoint, schema, error, rate-limit header, and example.
- Auth model: selected method, role/scope matrix, token lifetime, revocation strategy.
- Error model conforming to the standard envelope with documented error codes.
- Idempotency map: which endpoints require
Idempotency-Key, scope, TTL. - Observability notes: per-endpoint span names, SLO class, log fields, audit events.
- Implementation checklist result.
Evidence Produced
| Category | Artifact | Format | Example |
|---|---|---|---|
| Correctness | OpenAPI contract | Markdown doc plus OpenAPI YAML covering paths, schemas, and error responses | docs/api/openapi-checkout.yml |
| Correctness | Contract test results | CI log or recorded report from API contract tests against the OpenAPI spec | docs/api/contract-tests-2026-04-16.md |
References
- references/rest-conventions.md — URLs, methods, status codes, envelope, pagination, middleware order, health checks.
- references/openapi-workflow.md — spec-first workflow, OpenAPI 3.1 skeleton, versioning, HATEOAS, HTTP caching, GraphQL decision.
- references/auth-and-security.md — headers, CORS, auth-method selection table, API key, JWT, OAuth2, rate limiting, idempotency keys.
- references/implementation-checklist.md — pre-merge checklist and observability contract handed to
observability-monitoring. - Companion skill:
graphql-patterns— schema-first Apollo Server + TypeScript patterns when choosing GraphQL over REST for client-shaped reads.
Prerequisites
Load these skills first:
system-architecture-design— produces the context map and critical-flow table consumed below.database-design-engineering— produces the access-pattern list that shapes resource design.world-class-engineering— the shared release gate this skill ships into.
Load alongside:
vibe-security-skillfor threat modelling of the auth model produced here.graphql-securitywhenever building or auditing a GraphQL API.
When this skill applies
- A new service is being designed and needs its HTTP surface defined.
- A feature adds endpoints to an existing API and must follow the house contract.
- An existing API is being normalised for versioning, error envelope, or rate limits.
- A partner integration requires a published OpenAPI contract.
- Mobile or SDK work is blocked on a stable contract for code generation.
Inputs
| Artifact | Produced by | Required? | Why |
|---|---|---|---|
| Context map | system-architecture-design |
required | Defines service/module boundaries the API sits inside |
| Critical-flow table | system-architecture-design |
required | Supplies latency/availability targets for endpoints |
| Access-pattern list | database-design-engineering |
required | Read/write shapes drive resource model and pagination choices |
| Failure-mode list | system-architecture-design |
optional | Informs degradation behaviour on dependency outages |
| Threat model | vibe-security-skill |
optional | Informs auth, rate-limit, and abuse-case rules |
| Tenancy model | database-design-engineering |
required | Proves tenant isolation at the API boundary |
Outputs
| Artifact | Consumed by | Template |
|---|---|---|
| OpenAPI 3.1 contract | frontend, mobile, SDK, advanced-testing-strategy (contract tests) |
skill-composition-standards/references/openapi-contract.md |
| Error model | frontend, mobile, advanced-testing-strategy |
skill-composition-standards/references/error-model.md |
| Auth model | vibe-security-skill, mobile-rbac, ios-rbac, dual-auth-rbac |
inline in spec (components.securitySchemes) + role/scope matrix in auth-and-security.md |
| Idempotency map | reliability-engineering, stripe-payments |
inline table — see references/auth-and-security.md |
| Observability notes | observability-monitoring |
inline table — see references/implementation-checklist.md |
Non-negotiables
- OpenAPI spec is written before a single endpoint is implemented.
- Tenant scope comes from the auth token, never from the request body or query string.
- Every response carries the mandatory security headers from
auth-and-security.md. - Every POST that causes an external side effect (payment, email, webhook, inventory movement) requires an
Idempotency-Key. - Every new endpoint is added to the observability notes table before merge.
- Breaking changes never mutate an existing version; they ship as a new major version.
Decision rules
Auth-method selection
| Caller shape | Choose | Failure mode if wrong |
|---|---|---|
| Server-to-server, trusted partner, long-lived | API Key (SHA-256 hashed) | JWT: can't be revoked fast; raw-key storage: leak = instant compromise |
| Web app with user consent, third-party accessed | OAuth2 Authorization Code | Implicit flow: token leaks via URL history; ROPC: phishing vector |
| Service-to-service with scopes, standards-compliant | OAuth2 Client Credentials | API key: no standardised scopes or introspection |
| First-party mobile app / SPA | JWT access + refresh (short) | Long-lived JWT: revocation impossible; session cookie: breaks on iOS |
| Legacy / tightly-controlled client with no user flow | OAuth2 ROPC (last resort) | Credentials pass through the API surface — avoid when any alternative |
Versioning action
| Change | Action | Failure mode if wrong |
|---|---|---|
| Adding optional field, endpoint, or enum value | Ship in current version, mark non-breaking | Spawning a new version for a safe change: client churn |
| Removing or renaming a field | Ship as new major version, sunset old | Mutating existing version: silent parsing failures in clients |
| Changing response shape or required params | Ship as new major version, sunset old | As above |
| Bug fix that narrows behaviour clients may depend on | Ship behind a header flag, deprecate quietly | Silent fix: clients relying on the bug break in production |
Idempotency requirement
| Endpoint class | Require Idempotency-Key? |
TTL | Failure mode if skipped |
|---|---|---|---|
| Payment, refund, charge | yes | 24 h | Double charges on retry |
| Order/invoice creation | yes | 24 h | Duplicate orders on network retry |
| Outbound email / webhook dispatch | yes | 7 d | Duplicate user-visible side effects |
| Inventory movement | yes | 24 h | Phantom stock changes |
| Read-only (GET, HEAD) | no | n/a | n/a |
| Partial update without external effect | optional | 1 h | Benign — but worth enabling on sensitive ops |
Cache-Control choice
| Resource shape | Header | Failure mode if wrong |
|---|---|---|
| Public, rarely changes (prices) | public, max-age=3600 |
no-store: wastes bandwidth, slow clients |
| Per-user private | private, max-age=300 |
public: leaks via shared CDN cache |
| Sensitive or mutable (auth, cart) | no-store |
public: security incident |
GraphQL vs REST
| Situation | Choose |
|---|---|
| Multiple clients with diverging field needs | GraphQL |
| Public API, webhooks, file uploads | REST |
| Simple CRUD | REST |
| Real-time subscriptions | GraphQL subscriptions |
Failure mode if wrong: GraphQL-first for simple CRUD buys query-complexity DoS risk with no field-flexibility payoff; REST-first for multi-client heavy-reads pushes clients into over-fetch and N+1 round trips.
Design workflow (six steps)
- Define consumers, latency expectations, and trust boundaries.
- Model resources and actions around business concepts, not controller names.
- Write the OpenAPI contract, including auth, validation, errors, and pagination.
- Prove tenancy, authorisation, and idempotency rules before implementation.
- Design observability: request IDs, audit events, deprecation path, rate-limit telemetry.
- Validate that the API can evolve without breaking current consumers.
Full spec skeleton and per-step detail in references/openapi-workflow.md.
Response envelope
The canonical envelope produced by this skill — every downstream client depends on it:
{
"success": true,
"data": { "id": 123 },
"meta": { "page": 1, "per_page": 25, "total": 142 }
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The amount field is required.",
"documentation_url": "https://api.example.com/errors#VALIDATION_ERROR",
"fields": { "amount": ["Required"] }
}
}
Detail, status-code mapping, and pagination mechanics live in references/rest-conventions.md.
Anti-patterns
- Spec-after-code. The team writes endpoints and exports the OpenAPI spec from code annotations. Fix: draft the spec in a PR first, get sign-off from at least one consumer, then implement.
- Tenant from body.
POST /api/v1/invoices { "franchise_id": 42, "amount": 100 }. Fix: derivefranchise_idfrom the authenticated token server-side; ignore any tenant field on the wire. - 403 on wrong-tenant.
GET /api/v1/invoices/999returns403 Forbiddenwhen invoice 999 belongs to another tenant. Fix: return404 Not Found— 403 leaks that the resource exists. - Wildcard CORS with credentials.
Access-Control-Allow-Origin: *plusAccess-Control-Allow-Credentials: true. Fix: echo only origins from an allow-list; set credentials true only for those origins. - Raw API key storage.
INSERT INTO api_keys (key) VALUES ('sk_live_abc123'). Fix: storekey_hash = SHA-256(key), return the raw key once on creation, never again. - Unversioned breaking change. The team removes a field from
GET /api/v1/invoices/{id}because nobody "should" be using it. Fix: ship asv2, keepv1unchanged, emitDeprecation+Sunsetheaders onv1. - No idempotency on payments.
POST /api/v1/paymentscharges the card. Network retry charges it again. Fix: requireIdempotency-Keyheader, store(tenant, user, key) -> responsefor 24 h, replay the stored response on duplicate. - Unbounded page size.
GET /api/v1/invoices?per_page=100000. Fix: clampper_pageto a hard maximum (e.g. 100) server-side.
Read next
skill-composition-standards— normalisation standard this skill was rewritten against; templates for the OpenAPI contract and error model live there.observability-monitoring— consumes the observability notes table to build SLOs, alerts, and runbooks.reliability-engineering— consumes the idempotency map for retry and circuit-breaker design.deployment-release-engineering— consumes the versioning plan for migration choreography and rollback windows.vibe-security-skill— consumes the auth model to build the threat model and abuse-case list.
References
- references/rest-conventions.md — URLs, methods, status codes, envelope, pagination, middleware order, health checks, PHP controller skeleton.
- references/openapi-workflow.md — six-step workflow, OpenAPI 3.1 skeleton, versioning, HATEOAS, HTTP caching (ETags), GraphQL decision.
- references/auth-and-security.md — security headers, CORS, auth-method selection, API key, JWT, OAuth2, rate limiting, idempotency keys.
- references/implementation-checklist.md — pre-merge checklist, observability notes handed to
observability-monitoring, hand-off table to other skills. - references/skill-deep-dive.md — index redirect for the legacy deep-dive; kept for backward compatibility.
More from peterbamuhigire/skills-web-dev
google-play-store-review
Google Play Store compliance and review readiness for Android apps. Use
76multi-tenant-saas-architecture
Use when designing or reviewing a multi-tenant SaaS platform — tenant
62jetpack-compose-ui
Jetpack Compose UI standards for beautiful, sleek, minimalistic Android
49gis-mapping
Use for web apps that need Leaflet-first GIS mapping, location selection,
48saas-accounting-system
Implement a complete double-entry accounting system inside any SaaS app.
47manual-guide
Generate end-user manuals and reference guides for ERP modules. Use when
38