| name | api-designer |
| description | REST and GraphQL API design expertise covering REST maturity model, resource naming, pagination patterns, filtering and sorting, HATEOAS, versioning strategies, error response formats, rate limiting headers, and OpenAPI specification.
Use when the user asks about api designer, api designer best practices, or needs guidance on api designer implementation.
Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
|
| license | Apache-2.0 |
| metadata | {"author":"foundry-skills","version":"1.0.0","tags":"backend api-design guide","category":"backend-systems","subcategory":"api-design","depends":"","disclaimer":"none","difficulty":"intermediate"} |
API Designer
Purpose
Design consistent, intuitive, and evolvable HTTP APIs. This skill covers REST API design from resource modeling through error handling, pagination, versioning, and documentation with OpenAPI. GraphQL design considerations are included for comparison and hybrid architectures.
REST Maturity Model (Richardson)
Level 0: The Swamp of POX
- Single endpoint, single HTTP method (POST)
- RPC-style: POST /api { "action": "getUser", "id": 123 }
- Avoid this.
Level 1: Resources
- Multiple endpoints, one per resource
- POST /users, POST /users/123/delete
- Still misusing HTTP methods.
Level 2: HTTP Verbs (TARGET for most APIs)
- Resources + correct HTTP methods
- GET /users, POST /users, PUT /users/123, DELETE /users/123
- Correct status codes (200, 201, 204, 400, 404, etc.)
Level 3: HATEOAS (Hypermedia)
- Level 2 + hypermedia controls in responses
- Clients discover actions from response links
- Full REST (rarely implemented in practice)
Resource Naming Conventions
Rules
1. Use NOUNS, not verbs
GOOD: GET /users
BAD: GET /getUsers
2. Use PLURAL nouns
GOOD: /users, /orders, /products
BAD: /user, /order, /product
3. Use kebab-case for multi-word resources
GOOD: /order-items, /user-profiles
BAD: /orderItems, /user_profiles
4. Nest resources to show relationships (max 2 levels)
GOOD: /users/123/orders
BAD: /users/123/orders/456/items/789/reviews (too deep)
5. Use query parameters for filtering, not path segments
GOOD: GET /orders?status=pending&userId=123
BAD: GET /orders/pending/user/123
6. Actions on resources (when necessary)
POST /orders/123/cancel (state transition)
POST /users/123/verify (trigger action)
Standard HTTP Methods
GET /resources -> List resources (200)
GET /resources/:id -> Get single resource (200 or 404)
POST /resources -> Create resource (201 with Location header)
PUT /resources/:id -> Full replace (200 or 204)
PATCH /resources/:id -> Partial update (200 or 204)
DELETE /resources/:id -> Delete resource (204 or 200)
HEAD /resources/:id -> Same as GET but no body (check existence)
OPTIONS /resources -> Available methods (CORS preflight)
Standard Status Codes
2xx SUCCESS:
200 OK -> GET, PUT, PATCH with response body
201 Created -> POST (include Location header)
204 No Content -> DELETE, PUT/PATCH with no response body
3xx REDIRECTION:
301 Moved Permanently -> Resource permanently at new URL
304 Not Modified -> Conditional GET (ETag match)
4xx CLIENT ERROR:
400 Bad Request -> Validation error, malformed request
401 Unauthorized -> Missing or invalid authentication
403 Forbidden -> Authenticated but not authorized
404 Not Found -> Resource does not exist
405 Method Not Allowed -> HTTP method not supported
409 Conflict -> Resource state conflict (duplicate, version)
422 Unprocessable Entity -> Valid syntax but semantic errors
429 Too Many Requests -> Rate limit exceeded
5xx SERVER ERROR:
500 Internal Server Error -> Unexpected server failure
502 Bad Gateway -> Upstream service failure
503 Service Unavailable -> Temporary (include Retry-After header)
504 Gateway Timeout -> Upstream timeout
Pagination Patterns
Offset-Based Pagination
REQUEST:
GET /users?page=2&per_page=20
RESPONSE:
{
"data": [...],
"pagination": {
"page": 2,
"per_page": 20,
"total_items": 157,
"total_pages": 8,
"has_next": true,
"has_prev": true
},
"links": {
"first": "/users?page=1&per_page=20",
"prev": "/users?page=1&per_page=20",
"next": "/users?page=3&per_page=20",
"last": "/users?page=8&per_page=20"
}
}
PROS:
- Simple to implement
- Allows jumping to arbitrary page
- Total count available
CONS:
- Inconsistent with inserts/deletes during pagination
- Poor performance on large offsets (OFFSET N is O(N))
- Items can be skipped or duplicated between pages
Cursor-Based Pagination (Recommended for Large Datasets)
REQUEST:
GET /users?limit=20&after=eyJ0IjoxNjk...
RESPONSE:
{
"data": [...],
"pagination": {
"has_next": true,
"has_prev": true,
"next_cursor": "eyJ0IjoxNjk...",
"prev_cursor": "eyJ0IjoxNjg..."
}
}
PROS:
- Consistent pagination (no skips/dupes)
- Efficient for any position in dataset
- Works well with real-time data
CONS:
- Cannot jump to arbitrary page
- No total count (requires separate query)
- Cursor is opaque (not user-friendly)
CURSOR IMPLEMENTATION:
Encode the last item's sort key(s) as base64:
{ "created_at": "2025-01-15T10:30:00Z", "id": "abc123" }
-> base64 -> "eyJ0IjoxNjk..."
SQL:
WHERE (created_at, id) < (:cursor_created_at, :cursor_id)
ORDER BY created_at DESC, id DESC
LIMIT :limit + 1 -- get one extra to check has_next
Keyset Pagination
REQUEST:
GET /users?limit=20&created_before=2025-01-15T10:30:00Z&id_before=abc123
RESPONSE:
Same as cursor-based but with explicit keys instead of opaque cursor.
PROS: Transparent and debuggable
CONS: Exposes sort implementation
Filtering and Sorting
Filtering Patterns
Simple equality:
GET /users?status=active&role=admin
Operators (LHS brackets):
GET /orders?amount[gte]=100&amount[lte]=500
GET /users?name[contains]=john
GET /orders?created_at[after]=2025-01-01
Multiple values (comma-separated OR):
GET /users?role=admin,editor
Search:
GET /users?q=john+doe
Nested fields (dot notation):
GET /users?address.city=Austin
Sorting
Single sort:
GET /users?sort=created_at
GET /users?sort=-created_at (descending with - prefix)
Multi-sort:
GET /users?sort=-created_at,name (primary: created_at desc, secondary: name asc)
Alternative format:
GET /users?sort_by=created_at&sort_order=desc
Field Selection (Sparse Fieldsets)
GET /users?fields=id,name,email (only return these fields)
GET /users?include=orders,profile (include related resources)
GET /users?exclude=password_hash (exclude sensitive fields)
Error Response Format
Standard Error Envelope
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request body contains invalid data.",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Must be a valid email address."
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "Must be between 13 and 120.",
"meta": { "min": 13, "max": 120 }
}
],
Error Code Taxonomy
AUTHENTICATION:
AUTH_REQUIRED -> 401: No credentials provided
AUTH_INVALID -> 401: Invalid credentials
AUTH_EXPIRED -> 401: Token expired
AUTHORIZATION:
FORBIDDEN -> 403: Insufficient permissions
RESOURCE_FORBIDDEN -> 403: No access to this resource
VALIDATION:
VALIDATION_ERROR -> 400/422: Input validation failed
INVALID_FORMAT -> 400: Wrong data format
MISSING_FIELD -> 400: Required field missing
RESOURCE:
NOT_FOUND -> 404: Resource does not exist
ALREADY_EXISTS -> 409: Duplicate resource
CONFLICT -> 409: State conflict (version mismatch)
GONE -> 410: Resource permanently deleted
RATE_LIMIT:
RATE_LIMIT_EXCEEDED -> 429: Too many requests
SERVER:
INTERNAL_ERROR -> 500: Unexpected error
SERVICE_UNAVAILABLE -> 503: Temporary outage
Versioning Strategies
Decision Matrix
STRATEGY MECHANISM WHEN TO USE
-----------------------------------------------------------------------
URL Path /v1/users, /v2/users Simple, explicit, most common
Header Accept: application/vnd. More "RESTful", harder to test
api.v2+json
Query Param /users?version=2 Easy migration, but ugly
RECOMMENDATION: URL path versioning (/v1/) for simplicity and clarity.
Versioning Rules
1. Only bump major version for BREAKING changes:
- Removing a field
- Changing field type
- Changing resource structure
- Changing error format
2. NON-BREAKING changes (no version bump):
- Adding new fields (with defaults)
- Adding new endpoints
- Adding new query parameters
- Adding new enum values
3. Support at most 2 versions simultaneously
v1 (deprecated, sunset date set) and v2 (current)
4. Include deprecation headers:
Sunset: Sat, 01 Mar 2026 00:00:00 GMT
Deprecation: true
Link: <[reference URL]>; rel="successor-version"
Rate Limiting Headers
Response headers for rate-limited endpoints:
X-RateLimit-Limit: 100 # Max requests per window
X-RateLimit-Remaining: 67 # Remaining requests in window
X-RateLimit-Reset: 1705312800 # Unix timestamp when window resets
Retry-After: 30 # Seconds to wait (when 429 returned)
Alternative (IETF draft standard):
RateLimit-Policy: 100;w=3600 # 100 requests per 3600 seconds
RateLimit-Limit: 100
RateLimit-Remaining: 67
RateLimit-Reset: 42 # Seconds until reset (not timestamp)
HATEOAS
{
"id": "ord_123",
"status": "pending",
"total": 99.99,
"links": {
"self": { "href": "/orders/ord_123", "method": "GET" },
"cancel": { "href": "/orders/ord_123/cancel", "method": "POST" },
"pay": { "href": "/orders/ord_123/pay", "method": "POST" },
"items": { "href": "/orders/ord_123/items",
OpenAPI Specification
openapi: 3.1.0
info:
title: Users API
version: 1.0.0
description: User management API
contact:
email: api@example.com
servers:
- url: [reference URL]
description: Production
- url: [reference URL]
description: Staging
paths:
/users:
get:
operationId: listUsers
summary: List all users
tags: [Users]
parameters:
- name: page
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- BearerAuth: []
API Design Checklist
When to Use
Use this skill when:
- Designing or implementing api designer solutions
- Reviewing or improving existing api designer approaches
- Making architectural or implementation decisions about api designer
- Learning api designer patterns and best practices
- Troubleshooting api designer-related issues
Do NOT use this skill when:
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance
Output Format
# Api Designer Analysis
## Context Assessment
[Situation summary and constraints]
## Recommended Approach
[Primary recommendation with rationale]
## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]
## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]
## Next Steps
- [Immediate action item]
- [Follow-up action item]
Example
Input: "Help me implement api designer for a medium-scale production application"
Output: A structured analysis covering current state assessment, recommended api designer approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.
Edge Cases
- Legacy system integration: When api designer must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- Scale mismatch: When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- Team skill gaps: When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- Conflicting requirements: When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities