This is a template repository to start writing an API in Rust
| Concern | Choice |
|---|---|
| Web framework | Axum |
| Async runtime | Tokio |
| Serialization | Serde JSON |
| Error handling | thiserror |
| Validation | validator |
| Logging | tracing + tracing-subscriber |
| Config | config (TOML + env vars) |
| Request IDs | tower-http SetRequestId |
| CORS | tower-http CorsLayer |
| Timeout | tower-http TimeoutLayer |
| Tests | axum-test |
.
├── config/
│ ├── default.toml # base config, all environments
│ └── production.toml # production overrides
├── src/
│ ├── main.rs # entry point
│ ├── config.rs # AppConfig (typed config loading)
│ ├── state.rs # AppState (shared across handlers)
│ ├── errors.rs # ApiError → HTTP response mapping
│ ├── middleware/
│ │ └── tracing.rs # logging init
│ ├── models.rs # domain types + request/response DTOs
│ └── routes/
│ ├── mod.rs # router construction + middleware stack
│ ├── health.rs # GET /health
│ └── items.rs # CRUD /api/v1/items
└── tests/
└── .gitkeep # write your tests here
# Clone the template
git clone https://github.com/you/axum-template my-api
cd my-api
# Run in development
make dev
# Run tests
make test
# Build optimised release binary
make buildThe server starts on http://localhost:3000 by default.
Override any value via environment variables prefixed with APP__:
APP__SERVER__PORT=8080 cargo runOr add a config/local.toml (git-ignored):
[server]
port = 8080Environment (APP_ENV) can be development (default), production, or any custom name — a matching config/{APP_ENV}.toml file will be loaded automatically.
GET /health → 200 OK
GET /api/v1/items → 200 { data, total, page, per_page }
POST /api/v1/items → 201 Item
GET /api/v1/items/:id → 200 Item | 404
PUT /api/v1/items/:id → 200 Item | 404
DELETE /api/v1/items/:id → 204 | 404
{
"error": {
"code": "NOT_FOUND",
"message": "resource not found"
}
}Internal errors include a request_id for correlation with server logs.
# Build Docker image
make docker-build
# Run Docker image
make docker-run- Add a database – put an SQLx pool in
AppStateand swap the in-memory store inroutes/items.rsfor real queries. - Authentication – add a
middleware/auth.rsextractor and protect routes with.route_layer(...). - New resource – copy
routes/items.rs, rename types, andnestthe new router inroutes/mod.rs.