rust 41 lines · 7 steps

Building a create endpoint in Axum

An Axum handler deserializes JSON, inserts a row with sqlx, and returns 201 with a Location header.

Explained by highlit
1#[derive(Deserialize)]
2pub struct CreateArticle {
3 title: String,
4 body: String,
5}
6 
7#[derive(Serialize)]
8pub struct Article {
9 id: Uuid,
10 title: String,
11 body: String,
12 created_at: DateTime<Utc>,
13}
14 
15pub async fn create_article(
16 State(pool): State<PgPool>,
17 Json(payload): Json<CreateArticle>,
18) -> Result<(StatusCode, HeaderMap, Json<Article>), AppError> {
19 let article = sqlx::query_as!(
20 Article,
21 r#"
22 INSERT INTO articles (id, title, body, created_at)
23 VALUES ($1, $2, $3, now())
24 RETURNING id, title, body, created_at
25 "#,
26 Uuid::new_v4(),
27 payload.title,
28 payload.body,
29 )
30 .fetch_one(&pool)
31 .await?;
32 
33 let mut headers = HeaderMap::new();
34 headers.insert(
35 LOCATION,
36 HeaderValue::from_str(&format!("/articles/{}", article.id))
37 .map_err(|_| AppError::Internal)?,
38 );
39 
40 Ok((StatusCode::CREATED, headers, Json(article)))
41}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Axum extractors let a handler declare exactly what it needs from state and the request body in its signature.
  2. 2sqlx's query_as! maps a RETURNING row straight into a typed struct with compile-time-checked SQL.
  3. 3Returning a tuple of status, headers, and JSON lets one handler shape a complete HTTP response.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a create endpoint in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code