Specify a webhook-driven task for OpenClaw
Describe event inputs, validation, deduplication, and intended actions before integration work.
5,439,582 AI resources indexedWorking toward the world’s largest AI resource index.
RESTful and GraphQL API design principles, patterns, and best practices
---
name: api-design-efd922286844
description: RESTful and GraphQL API design principles, patterns, and best practices
license: MIT
compatibility: opencode
metadata:
category: architecture
domain: backend
protocols: rest,graphql
---
## What I do
I provide expertise in designing robust, scalable, and maintainable APIs:
- **RESTful API Design**: Resource modeling, HTTP methods, status codes
- **GraphQL Schema Design**: Types, queries, mutations, subscriptions
- **API Versioning**: Strategies for evolving APIs without breaking clients
- **Error Handling**: Consistent error responses and problem details
- **Authentication & Authorization**: OAuth2, JWT, API keys, RBAC
- **Rate Limiting & Pagination**: Scalability and performance patterns
- **Documentation**: OpenAPI/Swagger, GraphQL introspection
## When to use me
Load this skill when you need to:
- Design a new API from scratch
- Refactor or version an existing API
- Implement consistent error handling
- Add authentication/authorization
- Optimize API performance
- Document API contracts
## REST API Principles
### 1. Resource-Oriented Design
```
GET /users # List users
POST /users # Create user
GET /users/:id # Get user
PUT /users/:id # Update user (full)
PATCH /users/:id # Update user (partial)
DELETE /users/:id # Delete user
# Nested resources
GET /users/:id/posts # List user's posts
POST /users/:id/posts # Create post for user
```
### 2. HTTP Status Codes
```
2xx Success
200 OK - Successful GET, PUT, PATCH, DELETE
201 Created - Successful POST
204 No Content - Successful DELETE with no response body
4xx Client Errors
400 Bad Request - Invalid input
401 Unauthorized - Missing or invalid authentication
403 Forbidden - Authenticated but not authorized
404 Not Found - Resource doesn't exist
409 Conflict - Conflict with current state
422 Unprocessable - Validation errors
5xx Server Errors
500 Internal Server Error
503 Service Unavailable
```
### 3. Consistent Error Response Format
```typescript
interface ProblemDetails {
type: string; // URI reference to problem type
title: string; // Short, human-readable summary
status: number; // HTTP status code
detail?: string; // Human-readable explanation
instance?: string; // URI reference to specific occurrence
errors?: Record<string, string[]>; // Validation errors
}
// Example
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid fields",
"instance": "/users",
"errors": {
"email": ["Email is required", "Email must be valid"],
"age": ["Age must be at least 18"]
}
}
```
### 4. Pagination
```typescript
// Cursor-based (recommended for large datasets)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"pagination": {
"nextCursor": "eyJpZCI6MTQzfQ",
"hasMore": true
}
}
// Offset-based (simpler, but less performant)
GET /users?page=2&limit=20
{
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 150,
"totalPages": 8
}
}
```
### 5. Filtering, Sorting, Field Selection
```
# Filtering
GET /users?status=active&role=admin
# Sorting
GET /users?sort=createdAt:desc,name:asc
# Field selection (sparse fieldsets)
GET /users?fields=id,name,email
# Combined
GET /users?status=active&sort=name:asc&fields=id,name&limit=50
```
## GraphQL Schema Design
### 1. Type System
```graphql
type User {
id: ID!
email: String!
name: String!
posts: [Post!]!
createdAt: DateTime!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
published: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
type Query {
user(id: ID!): User
users(filter: UserFilter, page: PageInput): UserConnection!
post(id: ID!): Post
posts(filter: PostFilter, page: PageInput): PostConnection!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
email: String!
name: String!
password: String!
}
input UserFilter {
status: UserStatus
role: UserRole
search: String
}
```
### 2. Connection Pattern (Relay-style pagination)
```graphql
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
```
### 3. Error Handling
```typescript
// Use union types for operation results
type CreateUserResult = User | ValidationError | EmailTakenError
type ValidationError {
message: String!
fields: [FieldError!]!
}
type FieldError {
field: String!
message: String!
}
```
## API Versioning Strategies
### 1. URL Versioning (Explicit)
```
/v1/users
/v2/users
```
### 2. Header Versioning (Preferred)
```
GET /users
Accept: application/vnd.myapi.v2+json
```
### 3. Query Parameter
```
GET /users?version=2
```
### 4. GraphQL Schema Stitching
```graphql
# Deprecate fields gradually
type User {
id: ID!
name: String! @deprecated(reason: "Use firstName and lastName instead")
firstName: String!
lastName: String!
}
```
## Authentication & Authorization
### 1. JWT Bearer Tokens
```typescript
// Request
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
// Middleware
interface JWTPayload {
sub: string; // User ID
email: string;
role: string;
iat: number; // Issued at
exp: number; // Expiration
}
const authenticateJWT = (token: string): JWTPayload => {
return jwt.verify(token, process.env.JWT_SECRET);
};
```
### 2. API Keys
```typescript
// Request
X-API-Key: sk_live_1234567890abcdef
// Rate limiting per key
interface APIKey {
key: string;
userId: string;
rateLimit: number;
expiresAt?: Date;
}
```
### 3. Role-Based Access Control
```typescript
enum Permission {
READ_USERS = 'users:read',
WRITE_USERS = 'users:write',
DELETE_USERS = 'users:delete',
}
const authorize = (required: Permission[]) => {
return (req, res, next) => {
const userPermissions = req.user.permissions;
const hasPermission = required.every(p =>
userPermissions.includes(p)
);
if (!hasPermission) {
return res.status(403).json({
type: 'forbidden',
title: 'Forbidden',
status: 403,
});
}
next();
};
};
// Usage
app.delete('/users/:id',
authenticateJWT,
authorize([Permission.DELETE_USERS]),
deleteUser
);
```
## Rate Limiting
### 1. Token Bucket Algorithm
```typescript
interface RateLimiter {
limit: number; // Max requests
window: number; // Time window in seconds
remaining: number;
resetAt: Date;
}
// Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1640995200
```
### 2. Response when rate limited
```typescript
// HTTP 429 Too Many Requests
{
"type": "rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the rate limit. Try again later.",
"retryAfter": 3600
}
// Header
Retry-After: 3600
```
## API Documentation
### OpenAPI 3.0 Example
```yaml
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
required:
- id
- email
properties:
id:
type: string
email:
type: string
format: email
```
## Best Practices
1. **Use nouns for resources, not verbs**: `/users` not `/getUsers`
2. **Use plural nouns**: `/users` not `/user`
3. **Return proper status codes**: Don't return 200 for errors
4. **Include request IDs**: For tracing and debugging
5. **Version your API**: Plan for evolution
6. **Validate input**: Use schemas (JSON Schema, Zod, etc.)
7. **Log everything**: Requests, responses, errors
8. **Implement CORS properly**: For web clients
9. **Use HTTPS**: Always, no exceptions
10. **Document everything**: OpenAPI, examples, guides
## References
- RESTful Web APIs by Leonard Richardson
- GraphQL Best Practices: graphql.org/learn/best-practices
- RFC 7807: Problem Details for HTTP APIs
- OpenAPI Specification: swagger.io/specification
---
name: api-design-efd922286844
description: RESTful and GraphQL API design principles, patterns, and best practices
license: MIT
compatibility: opencode
metadata:
category: architecture
domain: backend
protocols: rest,graphql
---
## What I do
I provide expertise in designing robust, scalable, and maintainable APIs:
- **RESTful API Design**: Resource modeling, HTTP methods, status codes
- **GraphQL Schema Design**: Types, queries, mutations, subscriptions
- **API Versioning**: Strategies for evolving APIs without breaking clients
- **Error Handling**: Consistent error responses and problem details
- **Authentication & Authorization**: OAuth2, JWT, API keys, RBAC
- **Rate Limiting & Pagination**: Scalability and performance patterns
- **Documentation**: OpenAPI/Swagger, GraphQL introspection
## When to use me
Load this skill when you need to:
- Design a new API from scratch
- Refactor or version an existing API
- Implement consistent error handling
- Add authentication/authorization
- Optimize API performance
- Document API contracts
## REST API Principles
### 1. Resource-Oriented Design
```
GET /users # List users
POST /users # Create user
GET /users/:id # Get user
PUT /users/:id # Update user (full)
PATCH /users/:id # Update user (partial)
DELETE /users/:id # Delete user
# Nested resources
GET /users/:id/posts # List user's posts
POST /users/:id/posts # Create post for user
```
### 2. HTTP Status Codes
```
2xx Success
200 OK - Successful GET, PUT, PATCH, DELETE
201 Created - Successful POST
204 No Content - Successful DELETE with no response body
4xx Client Errors
400 Bad Request - Invalid input
401 Unauthorized - Missing or invalid authentication
403 Forbidden - Authenticated but not authorized
404 Not Found - Resource doesn't exist
409 Conflict - Conflict with current state
422 Unprocessable - Validation errors
5xx Server Errors
500 Internal Server Error
503 Service Unavailable
```
### 3. Consistent Error Response Format
```typescript
interface ProblemDetails {
type: string; // URI reference to problem type
title: string; // Short, human-readable summary
status: number; // HTTP status code
detail?: string; // Human-readable explanation
instance?: string; // URI reference to specific occurrence
errors?: Record<string, string[]>; // Validation errors
}
// Example
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid fields",
"instance": "/users",
"errors": {
"email": ["Email is required", "Email must be valid"],
"age": ["Age must be at least 18"]
}
}
```
### 4. Pagination
```typescript
// Cursor-based (recommended for large datasets)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"pagination": {
"nextCursor": "eyJpZCI6MTQzfQ",
"hasMore": true
}
}
// Offset-based (simpler, but less performant)
GET /users?page=2&limit=20
{
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 150,
"totalPages": 8
}
}
```
### 5. Filtering, Sorting, Field Selection
```
# Filtering
GET /users?status=active&role=admin
# Sorting
GET /users?sort=createdAt:desc,name:asc
# Field selection (sparse fieldsets)
GET /users?fields=id,name,email
# Combined
GET /users?status=active&sort=name:asc&fields=id,name&limit=50
```
## GraphQL Schema Design
### 1. Type System
```graphql
type User {
id: ID!
email: String!
name: String!
posts: [Post!]!
createdAt: DateTime!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
published: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
type Query {
user(id: ID!): User
users(filter: UserFilter, page: PageInput): UserConnection!
post(id: ID!): Post
posts(filter: PostFilter, page: PageInput): PostConnection!
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
email: String!
name: String!
password: String!
}
input UserFilter {
status: UserStatus
role: UserRole
search: String
}
```
### 2. Connection Pattern (Relay-style pagination)
```graphql
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type UserEdge {
node: User!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
```
### 3. Error Handling
```typescript
// Use union types for operation results
type CreateUserResult = User | ValidationError | EmailTakenError
type ValidationError {
message: String!
fields: [FieldError!]!
}
type FieldError {
field: String!
message: String!
}
```
## API Versioning Strategies
### 1. URL Versioning (Explicit)
```
/v1/users
/v2/users
```
### 2. Header Versioning (Preferred)
```
GET /users
Accept: application/vnd.myapi.v2+json
```
### 3. Query Parameter
```
GET /users?version=2
```
### 4. GraphQL Schema Stitching
```graphql
# Deprecate fields gradually
type User {
id: ID!
name: String! @deprecated(reason: "Use firstName and lastName instead")
firstName: String!
lastName: String!
}
```
## Authentication & Authorization
### 1. JWT Bearer Tokens
```typescript
// Request
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
// Middleware
interface JWTPayload {
sub: string; // User ID
email: string;
role: string;
iat: number; // Issued at
exp: number; // Expiration
}
const authenticateJWT = (token: string): JWTPayload => {
return jwt.verify(token, process.env.JWT_SECRET);
};
```
### 2. API Keys
```typescript
// Request
X-API-Key: sk_live_1234567890abcdef
// Rate limiting per key
interface APIKey {
key: string;
userId: string;
rateLimit: number;
expiresAt?: Date;
}
```
### 3. Role-Based Access Control
```typescript
enum Permission {
READ_USERS = 'users:read',
WRITE_USERS = 'users:write',
DELETE_USERS = 'users:delete',
}
const authorize = (required: Permission[]) => {
return (req, res, next) => {
const userPermissions = req.user.permissions;
const hasPermission = required.every(p =>
userPermissions.includes(p)
);
if (!hasPermission) {
return res.status(403).json({
type: 'forbidden',
title: 'Forbidden',
status: 403,
});
}
next();
};
};
// Usage
app.delete('/users/:id',
authenticateJWT,
authorize([Permission.DELETE_USERS]),
deleteUser
);
```
## Rate Limiting
### 1. Token Bucket Algorithm
```typescript
interface RateLimiter {
limit: number; // Max requests
window: number; // Time window in seconds
remaining: number;
resetAt: Date;
}
// Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1640995200
```
### 2. Response when rate limited
```typescript
// HTTP 429 Too Many Requests
{
"type": "rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the rate limit. Try again later.",
"retryAfter": 3600
}
// Header
Retry-After: 3600
```
## API Documentation
### OpenAPI 3.0 Example
```yaml
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
responses:
'200':
description: Success
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
required:
- id
- email
properties:
id:
type: string
email:
type: string
format: email
```
## Best Practices
1. **Use nouns for resources, not verbs**: `/users` not `/getUsers`
2. **Use plural nouns**: `/users` not `/user`
3. **Return proper status codes**: Don't return 200 for errors
4. **Include request IDs**: For tracing and debugging
5. **Version your API**: Plan for evolution
6. **Validate input**: Use schemas (JSON Schema, Zod, etc.)
7. **Log everything**: Requests, responses, errors
8. **Implement CORS properly**: For web clients
9. **Use HTTPS**: Always, no exceptions
10. **Document everything**: OpenAPI, examples, guides
## References
- RESTful Web APIs by Leonard Richardson
- GraphQL Best Practices: graphql.org/learn/best-practices
- RFC 7807: Problem Details for HTTP APIs
- OpenAPI Specification: swagger.io/specification
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.