Marketplace api-design
REST API design best practices for consistent, intuitive APIs
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/benny9193/api-design" ~/.claude/skills/aiskillstore-marketplace-api-design && rm -rf "$T"
manifest:
skills/benny9193/api-design/SKILL.mdsource content
API Design Principles
Design APIs that are intuitive, consistent, and a joy to use.
URL Structure
Resources as Nouns
# GOOD - nouns GET /users GET /users/123 GET /users/123/orders # BAD - verbs GET /getUsers GET /fetchUserById/123 POST /createNewUser
Plural Resource Names
# GOOD - plural GET /users GET /orders GET /products # BAD - singular GET /user GET /order
Hierarchical Relationships
# Parent-child relationships GET /users/123/orders # Orders for user 123 GET /orders/456/items # Items in order 456 # Avoid deep nesting (max 2 levels) # BAD GET /users/123/orders/456/items/789/reviews # GOOD - flatten when needed GET /order-items/789/reviews
HTTP Methods
| Method | Usage | Idempotent | Safe |
|---|---|---|---|
| GET | Read resource | Yes | Yes |
| POST | Create resource | No | No |
| PUT | Replace resource | Yes | No |
| PATCH | Partial update | Yes | No |
| DELETE | Remove resource | Yes | No |
GET /users # List users POST /users # Create user GET /users/123 # Get user 123 PUT /users/123 # Replace user 123 PATCH /users/123 # Update user 123 DELETE /users/123 # Delete user 123
Request/Response Format
Consistent JSON Structure
// Success response { "data": { "id": "123", "name": "John Doe", "email": "john@example.com" } } // Collection response { "data": [ { "id": "123", "name": "John" }, { "id": "456", "name": "Jane" } ], "meta": { "total": 100, "page": 1, "perPage": 20 } } // Error response { "error": { "code": "VALIDATION_ERROR", "message": "Invalid email format", "details": [ { "field": "email", "message": "Must be a valid email" } ] } }
Use camelCase
// GOOD { "firstName": "John", "lastName": "Doe", "emailAddress": "john@example.com" } // BAD - inconsistent { "first_name": "John", "LastName": "Doe", "email-address": "john@example.com" }
Status Codes
Success (2xx)
200 OK - GET, PUT, PATCH success 201 Created - POST success (include Location header) 204 No Content - DELETE success
Client Errors (4xx)
400 Bad Request - Invalid syntax, validation error 401 Unauthorized - No/invalid authentication 403 Forbidden - Authenticated but not allowed 404 Not Found - Resource doesn't exist 409 Conflict - State conflict (duplicate, version) 422 Unprocessable - Valid syntax but semantic error 429 Too Many Requests - Rate limited
Server Errors (5xx)
500 Internal Server Error - Unexpected error 502 Bad Gateway - Upstream service failed 503 Service Unavailable - Temporarily unavailable 504 Gateway Timeout - Upstream timeout
Pagination
Offset-based (simple)
GET /users?page=2&perPage=20 Response: { "data": [...], "meta": { "total": 100, "page": 2, "perPage": 20, "totalPages": 5 }, "links": { "first": "/users?page=1&perPage=20", "prev": "/users?page=1&perPage=20", "next": "/users?page=3&perPage=20", "last": "/users?page=5&perPage=20" } }
Cursor-based (scalable)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20 Response: { "data": [...], "meta": { "hasMore": true, "nextCursor": "eyJpZCI6MTQzfQ" } }
Filtering & Sorting
Filtering
GET /users?status=active GET /users?role=admin&status=active GET /users?createdAt[gte]=2024-01-01 GET /users?name[contains]=john
Sorting
GET /users?sort=name # Ascending GET /users?sort=-createdAt # Descending (prefix -) GET /users?sort=lastName,firstName
Field Selection
GET /users?fields=id,name,email GET /users/123?fields=id,name,email
Versioning
URL Path (recommended)
GET /v1/users GET /v2/users
Header
GET /users Accept: application/vnd.api+json;version=2
Authentication
Bearer Token
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
API Key
X-API-Key: sk_live_abc123 # Or in query (less secure) GET /users?api_key=sk_live_abc123
Rate Limiting
Include headers:
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1640995200 Retry-After: 60
Documentation
Every endpoint needs:
- Description of what it does
- Request parameters with types
- Request body schema
- Response schema for each status code
- Example request/response
- Error cases
# OpenAPI example /users: post: summary: Create a new user requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUser' responses: '201': description: User created content: application/json: schema: $ref: '#/components/schemas/User' '400': description: Validation error
Common Mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Verbs in URLs | | Use |
| Inconsistent naming | Mix of cases | Pick one (camelCase) |
| Wrong status codes | 200 for errors | Use 4xx/5xx appropriately |
| No pagination | Memory issues | Always paginate collections |
| Breaking changes | Clients break | Version your API |
| No rate limiting | Abuse | Implement limits |
| Exposing internals | Security risk | Transform responses |
Checklist
- URLs use nouns, not verbs
- HTTP methods used correctly
- Consistent response format
- Appropriate status codes
- Pagination for collections
- Filtering and sorting support
- Rate limiting implemented
- Authentication documented
- Errors are descriptive
- API is versioned