API Design Basics
9 examples for HTTP API design in Rust services - 6 basic and 3 intermediate.
Prerequisites
[dependencies]
axum = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"- Patterns here apply across Axum, Actix, and tonic HTTP gateways.
- Pair with serde DTOs at the HTTP boundary.
Basic Examples
1. Resource URLs
Nouns in paths, verbs in HTTP methods.
GET /users
POST /users
GET /users/{id}
PATCH /users/{id}
DELETE /users/{id}
- Plural resource names.
- Avoid RPC-style
/createUserfor CRUD. - Nest sub-resources:
/users/{id}/orders.
Related: GraphQL in Rust - alternative query model
2. Status Codes
Map outcomes to HTTP semantics.
201 Created - POST success with resource
204 No Content - DELETE success
409 Conflict - duplicate unique field
422 Unprocessable Entity - validation failure
- Do not return 200 for errors.
- 401 unauthenticated vs 403 forbidden.
- 429 when rate limited.
3. Error Envelope
Stable machine-readable errors.
{"error":{"code":"invalid_email","message":"Email format invalid","field":"email"}}- Include
code,message, optionalfield. - Log correlation ID server-side only.
- Never expose stack traces.
Related: Input Validation & Injection - validation errors
4. Versioning
Explicit API versions.
/v1/users
Accept: application/vnd.example.v1+json
- URL prefix is simplest for public APIs.
- Document deprecation timelines.
- Avoid silent breaking changes.
5. Pagination
Cursor-based listing.
GET /items?limit=20&cursor=eyJpZCI6MTB9
- Prefer cursors over OFFSET on large tables.
- Return
next_cursorin response body. - Cap maximum
limit.
6. Idempotency
Safe retries for POST.
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
- Store key + response hash in Redis or SQL.
- Return same response on duplicate key within TTL.
- Required for payment and create operations.
Related: Retries, Timeouts & Backoff - client retries
Intermediate Examples
7. Content Negotiation
JSON default with explicit content type.
// handlers return Json<T> - Axum sets application/json- Support
Acceptheader if multi-format. - Document charset UTF-8 for JSON.
8. Problem Details (optional standard)
RFC 7807 application/problem+json for errors.
{"type":"https://api.example.com/errors/validation","title":"Validation failed","status":422}- Standard fields:
type,title,status,detail. - Align with client SDK generators.
9. OpenAPI Metadata
Describe API for consumers.
// use utoipa::ToSchema on DTOs and utoipa::path on handlers- Keep OpenAPI generated from code where possible.
- Publish at
/docsonly in non-prod or behind auth.
Related: APIs & Security Best Practices - full baseline
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.