| name | api-designer |
| description | Designs and reviews REST, GraphQL, and gRPC APIs following industry best practices. Use when creating new API endpoints, reviewing API contracts, generating OpenAPI/Swagger specifications, designing authentication flows, or optimizing API performance and developer experience. |
API Designer Skill
This skill helps design, review, and implement APIs following industry best practices. Use this whenever you need to create new APIs, review existing API designs, generate specifications, or improve API developer experience.
API Design Principles
1. REST API Fundamentals
| Principle | Description |
|---|
| Resource-Oriented | URLs represent resources, not actions |
| Stateless | Each request contains all needed information |
| Uniform Interface | Consistent patterns across endpoints |
| HATEOAS | Responses include navigation links |
| Cacheable | Responses indicate cacheability |
2. HTTP Methods
| Method | Purpose | Idempotent | Safe | Request Body |
|---|
GET | Read resource | ✅ | ✅ | ❌ |
POST | Create resource | ❌ | ❌ | ✅ |
PUT | Replace resource | ✅ | ❌ | ✅ |
PATCH | Partial update | ❌ | ❌ | ✅ |
DELETE | Remove resource | ✅ | ❌ | ❌ |
HEAD | Get headers only | ✅ | ✅ | ❌ |
OPTIONS | Get allowed methods | ✅ | ✅ | ❌ |
3. HTTP Status Codes
Success (2xx):
| Code | Meaning | Use Case |
|---|
200 | OK | Successful GET, PUT, PATCH |
201 | Created | Successful POST |
202 | Accepted | Async operation started |
204 | No Content | Successful DELETE |
Client Errors (4xx):
| Code | Meaning | Use Case |
|---|
400 | Bad Request | Invalid input/validation error |
401 | Unauthorized | Missing/invalid authentication |
403 | Forbidden | Valid auth but insufficient permissions |
404 | Not Found | Resource doesn't exist |
405 | Method Not Allowed | Wrong HTTP method |
409 | Conflict | Duplicate/conflict with current state |
422 | Unprocessable Entity | Semantic validation error |
429 | Too Many Requests | Rate limit exceeded |
Server Errors (5xx):
| Code | Meaning | Use Case |
|---|
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Upstream service error |
503 | Service Unavailable | Maintenance/overload |
504 | Gateway Timeout | Upstream timeout |
URL Design
Resource Naming Conventions
# ✅ GOOD - Nouns, plural, lowercase, hyphens
GET /api/v1/users
GET /api/v1/users/123
GET /api/v1/users/123/orders
GET /api/v1/order-items
# ❌ BAD - Verbs, singular, camelCase
GET /api/v1/getUser
GET /api/v1/User/123
GET /api/v1/createOrder
GET /api/v1/orderItems
Hierarchical Resources
# Parent-child relationships
GET /api/v1/users/123/orders # User's orders
GET /api/v1/users/123/orders/456 # Specific order
GET /api/v1/users/123/orders/456/items # Order items
# Limit nesting depth (max 2-3 levels)
# ❌ Too deep
GET /api/v1/users/123/orders/456/items/789/reviews
# ✅ Flatten with filters
GET /api/v1/reviews?order_item_id=789
Query Parameters
# Filtering
GET /api/v1/products?category=electronics&status=active
# Sorting (use + for asc, - for desc)
GET /api/v1/products?sort=-created_at,+name
# Pagination
GET /api/v1/products?page=2&per_page=20
GET /api/v1/products?offset=20&limit=20
GET /api/v1/products?cursor=eyJpZCI6MTIzfQ
# Field selection (sparse fieldsets)
GET /api/v1/users/123?fields=id,name,email
# Including related resources
GET /api/v1/orders/123?include=customer,items
Request/Response Design
Request Structure
{
"email": "user@example.com",
"name": "John Doe",
"password": "SecureP@ss123",
"preferences": {
"newsletter": true,
"language": "en"
}
}
Response Structure
{
"data": {
"id": "usr_123abc",
"type": "user",
"attributes": {
"email": "user@example.com",
"name": "John Doe",
"created_at": "2025-01-15T10:30:00Z"
},
"relationships": {
"orders": {
"links": {
"related": "/api/v1/users/usr_123abc/orders"
}
}
}
},
"meta": {
"request_id": "req_xyz789"
},
"links": {
"self": "/api/v1/users/usr_123abc"
}
}
Collection Response with Pagination
{
"data": [
{ "id": "usr_123", "name": "User 1" },
{ "id": "usr_456", "name": "User 2" }
],
"meta": {
"total_count": 150,
"page": 2,
"per_page": 20,
"total_pages": 8
},
"links": {
"self": "/api/v1/users?page=2&per_page=20",
"first": "/api/v1/users?page=1&per_page=20",
"prev": "/api/v1/users?page=1&per_page=20",
"next": "/api/v1/users?page=3&per_page=20",
"last": "/api/v1/users?page=8&per_page=20"
}
}
Error Response
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request could not be validated",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Email must be a valid email address"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "Password must be at least 8 characters"
}
],
"request_id": "req_xyz789",
"documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
}
}
Authentication & Authorization
Authentication Methods
X-API-Key: sk_live_abc123xyz
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Authorization: Bearer ACCESS_TOKEN
JWT Structure
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-123"
}
{
"sub": "usr_123abc",
"iat": 1704963600,
"exp": 1704967200,
"iss": "https://api.example.com",
"aud": "https://api.example.com",
"scope": "read:users write:users",
"roles": ["admin"],
"email": "user@example.com"
}
OAuth 2.0 Flows
# Authorization Code Flow (Web Apps)
1. Redirect to: /oauth/authorize?client_id=X&redirect_uri=Y&scope=Z&state=random
2. User authenticates and consents
3. Redirect back with: ?code=AUTH_CODE&state=random
4. Exchange code: POST /oauth/token (grant_type=authorization_code)
5. Receive: access_token + refresh_token
# Client Credentials Flow (Machine-to-Machine)
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=read:data
# Token Refresh
POST /oauth/token
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
Versioning Strategies
URL Path Versioning (Recommended)
GET /api/v1/users
GET /api/v2/users
Header Versioning
GET /api/users
Accept: application/vnd.example.v1+json
X-API-Version: 1
Query Parameter Versioning
GET /api/users?version=1
Version Deprecation
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Link: <https:
{
"data": { ... },
"warnings": [
{
"code": "DEPRECATED_VERSION",
"message": "API v1 is deprecated. Please migrate to v2 by Dec 31, 2025.",
"documentation_url": "https://docs.example.com/migration/v1-to-v2"
}
]
}
OpenAPI Specification
Basic Structure
openapi: 3.1.0
info:
title: User Management API
description: API for managing users and their resources
version: 1.0.0
contact:
name: API Support
email: api-support@example.com
url: https://example.com/support
license:
name: MIT
url: https://opensource.org/licenses/MIT
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 development
tags:
- name: Users
description: User management operations
- name: Orders
description: Order processing
security:
- BearerAuth: []
- ApiKeyAuth: []
Path Definition
paths:
/users:
get:
summary: List all users
description: Returns a paginated list of users
operationId: listUsers
tags:
- Users
parameters:
- name: page
in: query
description: Page number
schema:
type: integer
default: 1
minimum: 1
- name: per_page
in: query
description: Items per page
schema:
type: integer
default: 20
maximum: 100
- name: status
in: query
description: Filter by status
schema:
type: string
enum: [active, inactive, pending]
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
post:
summary: Create a user
description: Creates a new user account
operationId: createUser
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
examples:
basic:
summary: Basic user
value:
email: user@example.com
name: John Doe
password: SecureP@ss123
responses:
'201':
description: User created
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
$ref: '#/components/responses/ValidationError'
'409':
description: Email already exists
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users/{userId}:
parameters:
- name: userId
in: path
required: true
description: User ID
schema:
type: string
pattern: '^usr_[a-zA-Z0-9]+$'
get:
summary: Get user by ID
operationId: getUser
tags:
- Users
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
$ref: '#/components/responses/NotFound'
patch:
summary: Update user
operationId: updateUser
tags:
- Users
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserRequest'
responses:
'200':
description: User updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
delete:
summary: Delete user
operationId: deleteUser
tags:
- Users
responses:
'204':
description: User deleted
'404':
$ref: '#/components/responses/NotFound'
Schema Definitions
components:
schemas:
User:
type: object
required:
- id
- email
- name
- created_at
properties:
id:
type: string
pattern: '^usr_[a-zA-Z0-9]+$'
example: usr_123abc
readOnly: true
email:
type: string
format: email
example: user@example.com
name:
type: string
minLength: 1
maxLength: 100
example: John Doe
status:
type: string
enum: [active, inactive, pending]
default: pending
created_at:
type: string
format: date-time
readOnly: true
updated_at:
type: string
format: date-time
readOnly: true
CreateUserRequest:
type: object
required:
- email
- name
- password
properties:
email:
type: string
format: email
name:
type: string
minLength: 1
maxLength: 100
password:
type: string
minLength: 8
maxLength: 128
format: password
writeOnly: true
UpdateUserRequest:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 100
status:
type: string
enum: [active, inactive]
UserList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
meta:
$ref: '#/components/schemas/PaginationMeta'
links:
$ref: '#/components/schemas/PaginationLinks'
PaginationMeta:
type: object
properties:
total_count:
type: integer
page:
type: integer
per_page:
type: integer
total_pages:
type: integer
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
code:
type: string
message:
type: string
request_id:
type: string
responses:
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: NOT_FOUND
message: The requested resource was not found
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ValidationError:
description: Validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Rate limit exceeded
headers:
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
X-RateLimit-Reset:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
GraphQL API Design
Schema Definition
type Query {
user(id: ID!): User
users(
filter: UserFilter
pagination: PaginationInput
orderBy: UserOrderBy
): UserConnection!
me: User
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
deleteUser(id: ID!): DeleteUserPayload!
}
type User {
id: ID!
email: String!
name: String!
status: UserStatus!
createdAt: DateTime!
updatedAt: DateTime
orders(first: Int, after: String): OrderConnection!
profile: UserProfile
}
enum UserStatus {
ACTIVE
INACTIVE
PENDING
}
input UserFilter {
status: UserStatus
searchTerm: String
createdAfter: DateTime
createdBefore: DateTime
}
input PaginationInput {
first: Int
after: String
last: Int
before: String
}
input UserOrderBy {
field: UserOrderField!
direction: OrderDirection!
}
enum UserOrderField {
CREATED_AT
NAME
EMAIL
}
enum OrderDirection {
ASC
DESC
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
input CreateUserInput {
email: String!
name: String!
password: String!
}
type CreateUserPayload {
user: User
errors: [UserError!]
}
type UserError {
field: String
message: String!
code: String!
}
Rate Limiting
Headers
X-RateLimit-Limit: 1000 # Max requests per window
X-RateLimit-Remaining: 999 # Remaining requests
X-RateLimit-Reset: 1704963600 # Unix timestamp when limit resets
Retry-After: 60 # Seconds until retry (on 429)
Rate Limit Tiers
rate_limits:
anonymous:
requests_per_minute: 60
requests_per_hour: 1000
authenticated:
requests_per_minute: 600
requests_per_hour: 10000
premium:
requests_per_minute: 6000
requests_per_hour: 100000
endpoints:
/auth/login:
requests_per_minute: 5
burst: 3
/search:
requests_per_minute: 30
/export:
requests_per_day: 10
API Design Checklist
Resource Design
Request/Response
Security
Documentation
Developer Experience
Output Format
When designing an API, provide:
## API Design Proposal
### Resource: [Resource Name]
#### Endpoints
| Method | Path | Description |
|--------|------|-------------|
| GET | /resource | List all |
| POST | /resource | Create |
| GET | /resource/{id} | Get one |
| PATCH | /resource/{id} | Update |
| DELETE | /resource/{id} | Delete |
#### Request/Response Examples
[Include examples for each endpoint]
#### OpenAPI Specification
```yaml
[OpenAPI spec for the resource]
Implementation Notes
- [Important consideration 1]
- [Important consideration 2]
## Notes
- Design APIs for consumers, not implementation
- Consistency is more important than perfection
- Version from the start
- Document as you design
- Consider backwards compatibility
- Plan for deprecation