Backend API Skill
Build robust, well-documented APIs with clear contracts, proper error handling, and scalable architecture.
When to Use
Use this skill when the user wants to:
- Design or implement RESTful API endpoints
- Create GraphQL schemas and resolvers
- Handle authentication and authorization
- Work with database models and migrations
- Implement CRUD operations and data validation
- Create API documentation (OpenAPI/Swagger)
API Design Principles
- Clear contract: Define request/response formats explicitly.
- Consistent naming: Use RESTful conventions (GET, POST, PUT, DELETE) or GraphQL query structure.
- Versioning: Include API version in path (e.g.,
/api/v1/...) to manage breaking changes.
- Error handling: Return meaningful HTTP status codes and structured error messages.
- Documentation: Include clear examples and describe all fields (using OpenAPI/Swagger).
Implementation Examples
FastAPI (Python) - RESTful API
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
if item.price < 0:
raise HTTPException(status_code=400, detail="Price cannot be negative")
return item
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id != 1:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id, "name": "Sample Item", "price": 10.0}
Express (JavaScript/Node.js) - RESTful API
const express = require('express');
const app = express();
app.use(express.json());
let items = [{ id: 1, name: 'Item One', price: 10.0 }];
// Get all items with pagination
app.get('/api/v1/items', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const results = items.slice(startIndex, endIndex);
res.json({
page,
limit,
total: items.length,
data: results
});
});
// Create an item
app.post('/api/v1/items', (req, res) => {
const { name, price } = req.body;
if (!name || !price) {
return res.status(400).json({ error: 'Name and price are required' });
}
const newItem = { id: items.length + 1, name, price };
items.push(newItem);
res.status(201).json(newItem);
});
app.listen(3000, () => console.log('Server running on port 3000'));
Pagination and Filtering
- Offset-based: Use
limit and offset (or page) for simple datasets.
- Cursor-based: Use a unique identifier (e.g.,
after_id) for high-frequency updates to avoid skipping items.
- Filtering: Implement query parameters for filtering (e.g.,
/items?category=tech&sort=price_desc).
Common Pitfalls
- Improper Error Handling: Returning
200 OK with an error message in the body instead of correct HTTP status codes.
- Leaking Sensitive Info: Including stack traces or database details in production error responses.
- Lack of Rate Limiting: Leaving endpoints open to brute force or DoS attacks.
- Ignoring Pagination: Returning massive datasets in a single response, causing performance issues.
- Insecure Direct Object References (IDOR): Failing to check if the authenticated user has permission to access a specific resource ID.
Deliverables
- Complete API implementation (Controllers, Services, Models).
- Request/response examples and schemas.
- Comprehensive error handling strategy.
- Input validation logic.
- Interactive API documentation (Swagger/OpenAPI).
Quality Checklist
1---2name: backend-api3description: Build RESTful APIs, GraphQL endpoints, and database-driven backend services. Use when designing APIs, implementing CRUD operations, handling authentication, or working with backend logic.4---56# Backend API Skill78Build robust, well-documented APIs with clear contracts, proper error handling, and scalable architecture.910## When to Use1112Use this skill when the user wants to:13- Design or implement RESTful API endpoints14- Create GraphQL schemas and resolvers15- Handle authentication and authorization16- Work with database models and migrations17- Implement CRUD operations and data validation18- Create API documentation (OpenAPI/Swagger)1920## API Design Principles2122- **Clear contract**: Define request/response formats explicitly.23- **Consistent naming**: Use RESTful conventions (GET, POST, PUT, DELETE) or GraphQL query structure.24- **Versioning**: Include API version in path (e.g., `/api/v1/...`) to manage breaking changes.25- **Error handling**: Return meaningful HTTP status codes and structured error messages.26- **Documentation**: Include clear examples and describe all fields (using OpenAPI/Swagger).2728## Implementation Examples2930### FastAPI (Python) - RESTful API31```python32from fastapi import FastAPI, HTTPException, Depends33from pydantic import BaseModel3435app = FastAPI()3637class Item(BaseModel):38 name: str39 price: float4041@app.post("/items/", response_model=Item)42async def create_item(item: Item):43 if item.price < 0:44 raise HTTPException(status_code=400, detail="Price cannot be negative")45 return item4647@app.get("/items/{item_id}")48async def read_item(item_id: int):49 if item_id != 1:50 raise HTTPException(status_code=404, detail="Item not found")51 return {"item_id": item_id, "name": "Sample Item", "price": 10.0}52```5354### Express (JavaScript/Node.js) - RESTful API55```javascript56const express = require('express');57const app = express();58app.use(express.json());5960let items = [{ id: 1, name: 'Item One', price: 10.0 }];6162// Get all items with pagination63app.get('/api/v1/items', (req, res) => {64 const page = parseInt(req.query.page) || 1;65 const limit = parseInt(req.query.limit) || 10;66 const startIndex = (page - 1) * limit;67 const endIndex = page * limit;6869 const results = items.slice(startIndex, endIndex);70 res.json({71 page,72 limit,73 total: items.length,74 data: results75 });76});7778// Create an item79app.post('/api/v1/items', (req, res) => {80 const { name, price } = req.body;81 if (!name || !price) {82 return res.status(400).json({ error: 'Name and price are required' });83 }84 const newItem = { id: items.length + 1, name, price };85 items.push(newItem);86 res.status(201).json(newItem);87});8889app.listen(3000, () => console.log('Server running on port 3000'));90```9192## Pagination and Filtering9394- **Offset-based**: Use `limit` and `offset` (or `page`) for simple datasets.95- **Cursor-based**: Use a unique identifier (e.g., `after_id`) for high-frequency updates to avoid skipping items.96- **Filtering**: Implement query parameters for filtering (e.g., `/items?category=tech&sort=price_desc`).9798## Common Pitfalls99100- **Improper Error Handling**: Returning `200 OK` with an error message in the body instead of correct HTTP status codes.101- **Leaking Sensitive Info**: Including stack traces or database details in production error responses.102- **Lack of Rate Limiting**: Leaving endpoints open to brute force or DoS attacks.103- **Ignoring Pagination**: Returning massive datasets in a single response, causing performance issues.104- **Insecure Direct Object References (IDOR)**: Failing to check if the authenticated user has permission to access a specific resource ID.105106## Deliverables107108- Complete API implementation (Controllers, Services, Models).109- Request/response examples and schemas.110- Comprehensive error handling strategy.111- Input validation logic.112- Interactive API documentation (Swagger/OpenAPI).113114## Quality Checklist115116- [ ] Clear endpoint definitions following RESTful conventions.117- [ ] Proper use of HTTP status codes (200, 201, 400, 401, 403, 404, 500).118- [ ] Robust input validation for all request bodies and parameters.119- [ ] Error responses are structured and do not leak implementation details.120- [ ] API is documented with clear examples.121- [ ] Implementation includes pagination for large resource collections.