Projektowanie dobrego REST API to wiecej niz zwracanie JSON. Dobrze zaprojektowane API jest przewidywalne, spojne, bezpieczne i latwe w uzyciu. Ten przewodnik obejmuje najwazniejsze praktyki projektowania API REST.
1. Rzeczowniki w URI zasobow
API REST modeluja zasoby, nie akcje.
# Good - nouns representing resources
GET /api/v1/users # list users
GET /api/v1/users/123 # get user 123
POST /api/v1/users # create a user
PUT /api/v1/users/123 # replace user 123
PATCH /api/v1/users/123 # partially update user 123
DELETE /api/v1/users/123 # delete user 123
# Bad - verbs describing actions
GET /api/v1/getUsers
POST /api/v1/createUser
POST /api/v1/deleteUser/123
GET /api/v1/getUserById?id=123# Nested resources (one level deep)
GET /api/v1/users/123/orders # orders for user 123
GET /api/v1/users/123/orders/456 # order 456 for user 123
POST /api/v1/users/123/orders # create order for user 123
# For actions that don't map to CRUD, use sub-resources
POST /api/v1/users/123/activate # activate user (action)
POST /api/v1/orders/456/cancel # cancel order (action)
POST /api/v1/emails/789/resend # resend email2. Poprawne uzycie metod HTTP
Kazda metoda HTTP ma okreslone znaczenie semantyczne.
| Method | Purpose | Idempotent | Request Body |
|---|---|---|---|
GET | Read a resource | Yes | No |
POST | Create a resource | No | Yes |
PUT | Full replacement | Yes | Yes |
PATCH | Partial update | No* | Yes |
DELETE | Remove a resource | Yes | No |
3. Nazwy zasobow w liczbie mnogiej
Zawsze uzywaj rzeczownikow w liczbie mnogiej dla kolekcji.
# Good - consistent plural nouns
/api/v1/users
/api/v1/users/123
/api/v1/products
/api/v1/products/456/reviews
# Bad - mixing singular and plural
/api/v1/user # singular
/api/v1/user/123
/api/v1/productList # avoid "list" suffix4. Poprawne uzycie kodow statusu HTTP
Kody statusu mowia klientowi co sie stalo.
| Code | When to Use |
|---|---|
200 OK | Successful GET, PUT, PATCH, or DELETE |
201 Created | Successful POST that creates a resource |
204 No Content | Successful DELETE with no response body |
400 Bad Request | Malformed request syntax or invalid data |
401 Unauthorized | Missing or invalid authentication |
403 Forbidden | Authenticated but not authorized |
404 Not Found | Resource does not exist |
409 Conflict | Conflicting state (e.g., duplicate email) |
422 Unprocessable | Validation errors in request body |
429 Too Many Requests | Rate limit exceeded |
500 Internal Error | Unexpected server error |
5. Wersjonowanie API
Wersjonowanie chroni istniejacych konsumentow przy zmianach lamiacych kompatybilnosc.
# Strategy 1: URI versioning (most common)
GET /api/v1/users
GET /api/v2/users
# Strategy 2: Header versioning
GET /api/users
Accept: application/vnd.myapi.v2+json
# Strategy 3: Query parameter versioning
GET /api/users?version=2| Strategy | Pros | Cons |
|---|---|---|
| URI path | Simple, visible, cacheable | URI pollution |
| Header | Clean URIs | Harder to test, less visible |
| Query param | Easy to add | Cache-unfriendly, easy to forget |
6. Paginacja, filtrowanie i sortowanie
Kazdy endpoint zwracajacy kolekcje powinien wspierac paginacje.
# Offset-based pagination (simplest)
GET /api/v1/users?page=2&limit=25
GET /api/v1/users?offset=25&limit=25
# Cursor-based pagination (better for large datasets)
GET /api/v1/users?cursor=eyJpZCI6MTAwfQ&limit=25
# Response with pagination metadata
{
"data": [...],
"pagination": {
"total": 1250,
"page": 2,
"limit": 25,
"totalPages": 50,
"hasNext": true,
"hasPrev": true
}
}
# Filtering and sorting
GET /api/v1/products?category=electronics&minPrice=100&maxPrice=500
GET /api/v1/products?sort=price&order=asc
GET /api/v1/products?sort=-created_at # prefix with - for descending
GET /api/v1/users?fields=id,name,email # sparse fieldsets7. Format odpowiedzi bledow
Spojny format bledow pomaga klientom obslugiwac bledy programistycznie.
// Consistent error response format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"value": "not-an-email"
},
{
"field": "age",
"message": "Must be at least 18",
"value": 15
}
],
"requestId": "req_abc123",
"timestamp": "2026-01-15T10:30:00Z",
"docs": "https://api.example.com/docs/errors#VALIDATION_ERROR"
}
}
// Simple error (non-validation)
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "User with id 999 not found",
"requestId": "req_def456"
}
}8. Uwierzytelnianie i bezpieczenstwo
Bezpieczenstwo API jest bezdyskusyjne.
# Bearer token authentication (JWT)
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
# API key authentication
GET /api/v1/users
X-API-Key: sk_live_abc123def456
# OAuth 2.0 token request
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:users write:users- Always use HTTPS in production
- Never put secrets in query parameters (they appear in server logs)
- Use short-lived access tokens (15-60 min) with refresh tokens
- Implement CORS properly for browser-based clients
- Validate and sanitize all input to prevent injection attacks
- Use rate limiting to prevent brute-force attacks
9. Ograniczanie czestotliwosci
Rate limiting chroni API przed naduzyciami.
# Rate limit response headers (standard)
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000 # max requests per window
X-RateLimit-Remaining: 742 # requests remaining
X-RateLimit-Reset: 1706810400 # Unix timestamp when limit resets
Retry-After: 60 # seconds until next request (on 429)
# Rate limit exceeded response
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Limit: 1000/hour",
"retryAfter": 60
}
}10. HATEOAS i linki
HATEOAS dodaje odkrywalnosc do API.
// HATEOAS response example
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"status": "active",
"_links": {
"self": { "href": "/api/v1/users/123" },
"orders": { "href": "/api/v1/users/123/orders" },
"deactivate": {
"href": "/api/v1/users/123/deactivate",
"method": "POST"
}
}
}
// Paginated collection with HATEOAS links
{
"data": [...],
"_links": {
"self": { "href": "/api/v1/users?page=2&limit=25" },
"first": { "href": "/api/v1/users?page=1&limit=25" },
"prev": { "href": "/api/v1/users?page=1&limit=25" },
"next": { "href": "/api/v1/users?page=3&limit=25" },
"last": { "href": "/api/v1/users?page=50&limit=25" }
}
}Czesto zadawane pytania
PUT czy PATCH do aktualizacji?
PUT do pelnej zamiany, PATCH do czesciowej aktualizacji.
Czy URI powinny byc malymi literami?
Tak, uzywaj kebab-case malymi literami.
Jak obslugiwac zagniezdzone zasoby?
Ogranicz zagniezdanie do jednego poziomu.
Najlepsza metoda uwierzytelniania?
OAuth 2.0 z JWT dla aplikacji uzytkownikow.
GraphQL czy REST?
REST jest prostszy z lepszym cachem. GraphQL dla zlozonych potrzeb danych.
TL;DR
- Use nouns (not verbs) for resource URIs
- Use the correct HTTP method for each operation
- Always use plural resource names
- Return appropriate HTTP status codes
- Version your API from day one (URI path is simplest)
- Support pagination, filtering, and sorting for collections
- Use a consistent error response format
- Always use HTTPS and proper authentication
- Implement rate limiting with standard headers
- Consider HATEOAS for API discoverability
Stosowanie tych praktyk od poczatku oszczedza godziny refaktoryzacji.