Build a REST API in Rust with Axum
Axum is a popular Rust web framework from the Tokio team. Handlers are plain async functions, and "extractors" in their parameters pull data out of the request in a type-safe way.
Dependencies
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
The API
use axum::{
extract::{Path, State},
http::StatusCode,
routing::get,
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::{Arc, Mutex}};
#[derive(Clone, Serialize)]
struct Todo { id: u64, title: String, done: bool }
#[derive(Deserialize)]
struct NewTodo { title: String }
#[derive(Clone, Default)]
struct AppState { todos: Arc<Mutex<HashMap<u64, Todo>>> }
async fn list(State(state): State<AppState>) -> Json<Vec<Todo>> {
Json(state.todos.lock().unwrap().values().cloned().collect())
}
async fn create(State(state): State<AppState>, Json(input): Json<NewTodo>) -> (StatusCode, Json<Todo>) {
let mut todos = state.todos.lock().unwrap();
let id = todos.len() as u64 + 1;
let todo = Todo { id, title: input.title, done: false };
todos.insert(id, todo.clone());
(StatusCode::CREATED, Json(todo))
}
async fn get_one(State(state): State<AppState>, Path(id): Path<u64>) -> Result<Json<Todo>, StatusCode> {
state.todos.lock().unwrap().get(&id).cloned().map(Json).ok_or(StatusCode::NOT_FOUND)
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/todos", get(list).post(create))
.route("/todos/{id}", get(get_one))
.with_state(AppState::default());
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
How it fits together
Path,Query,JsonandStateare extractors; a malformed request is rejected before your handler runs.- Anything that implements
IntoResponsecan be returned: aJson, a status code, a tuple of both, or aResult. - Path parameters use
{id}syntax in Axum 0.8.
Next steps
- Swap the HashMap for PostgreSQL with
sqlxand a connection pool inAppState. - Add middleware from
tower-http: tracing, CORS, compression, timeouts. - Define an error enum that implements
IntoResponsefor consistent JSON errors.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.