Your API Is Your Product's Handshake
A well-designed API is a pleasure to integrate with. A poorly designed one creates support tickets, frustrated developers, and lost partnerships. We've built and consumed hundreds of APIs - here's what separates the good from the painful.
Core Principles
1. Resource-Based URL Design
URLs should represent resources (nouns), not actions (verbs):
| ❌ Bad | ✅ Good |
|---|---|
| GET /getUsers | GET /users |
| POST /createOrder | POST /orders |
| PUT /updateUser/123 | PUT /users/123 |
| DELETE /removeProduct/456 | DELETE /products/456 |
Nesting resources logically:
GET /users/123/orders- Orders belonging to user 123GET /orders/456/items- Items in order 456- But avoid nesting deeper than 2 levels - it gets unwieldy
2. HTTP Methods - Use Them Correctly
| Method | Purpose | Idempotent? | Response |
|---|---|---|---|
| GET | Retrieve resource(s) | Yes | 200 with data |
| POST | Create a new resource | No | 201 with created resource |
| PUT | Replace entire resource | Yes | 200 with updated resource |
| PATCH | Update specific fields | Yes | 200 with updated resource |
| DELETE | Remove a resource | Yes | 204 (no content) |
3. Status Codes - Be Specific
Don't return 200 for everything. Status codes exist to communicate what happened:
| Code | Meaning | When to Use |
|---|---|---|
| 200 | OK | Successful GET, PUT, PATCH |
| 201 | Created | Successful POST |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Invalid input data |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Authenticated but lacks permission |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate resource or state conflict |
| 422 | Unprocessable Entity | Validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server failure |
Pagination - Don't Return Everything
For any endpoint that returns a list, implement pagination:
{
"data": [...],
"meta": {
"page": 1,
"per_page": 20,
"total": 1543,
"total_pages": 78
},
"links": {
"self": "/api/v1/products?page=1",
"next": "/api/v1/products?page=2",
"last": "/api/v1/products?page=78"
}
}
Cursor-based pagination is better for large datasets:
GET /api/v1/events?after=eyJpZCI6MTAwfQ&limit=20
Error Handling - Be Helpful
When something goes wrong, tell the developer exactly what happened and how to fix it:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid fields",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"received": "not-an-email"
},
{
"field": "age",
"message": "Must be a positive integer",
"received": -5
}
],
"documentation": "https://api.example.com/docs/errors/validation"
}
}
Versioning Strategy
APIs evolve. Breaking changes happen. How you version determines how painful upgrades are for your consumers.
| Approach | Example | Pros | Cons |
|---|---|---|---|
| URL path | /api/v1/users | Clear, easy to implement | URLs change between versions |
| Header | Accept: application/vnd.api.v2+json | Clean URLs | Harder to test, discover |
| Query param | /api/users?version=2 | Easy to implement | Can be accidentally omitted |
Our recommendation: URL path versioning. It's explicit, discoverable, and makes it obvious which version documentation you should be reading.
Security - Non-Negotiable
- Always use HTTPS - no exceptions, even for internal APIs
- Implement rate limiting - protect against abuse and accidental overload
- Use OAuth 2.0 for authentication - don't build your own auth
- Validate all inputs server-side - never trust the client
- Don't expose internal errors - return generic messages to clients, log details internally
- Implement API keys for third-party access - with scoping and rotation
Advanced Patterns
Filtering, Sorting, and Field Selection
GET /api/v1/products?category=electronics&price_min=100&sort=-created_at&fields=id,name,price
Bulk Operations
For APIs that need to process multiple items:
POST /api/v1/products/bulk
{
"operations": [
{ "action": "create", "data": { "name": "Widget A" } },
{ "action": "update", "id": "123", "data": { "price": 29.99 } }
]
}
Webhooks for Real-Time Updates
Instead of clients polling your API, push events to them:
POST https://client-webhook-url.com/events
{
"event": "order.completed",
"data": { "order_id": "456", "total": 99.99 },
"timestamp": "2025-01-15T14:30:00Z"
}
Conclusion
API design is product design. Invest time upfront in consistent naming, clear error messages, comprehensive documentation, and thoughtful versioning. The developers integrating with your API will thank you - and your support team will have fewer tickets.
Building APIs for your application? Our web development team designs and builds APIs that scale. Let's discuss your project.


