rust 50 lines · 8 steps

Optimistic concurrency with ETags in Axum

An Axum handler uses If-Match and ETag headers to reject stale writes and prevent lost updates.

Explained by highlit
1use axum::{
2 extract::{Path, State},
3 http::{header, HeaderMap, StatusCode},
4 response::{IntoResponse, Response},
5 Json,
6};
7use serde::Deserialize;
8use std::sync::Arc;
9 
10#[derive(Deserialize)]
11pub struct UpdateArticle {
12 pub title: String,
13 pub body: String,
14}
15 
16pub async fn update_article(
17 State(repo): State<Arc<ArticleRepo>>,
18 Path(id): Path<i64>,
19 headers: HeaderMap,
20 Json(payload): Json<UpdateArticle>,
21) -> Response {
22 let if_match = match headers.get(header::IF_MATCH) {
23 Some(value) => value.to_str().unwrap_or_default().trim_matches('"').to_owned(),
24 None => {
25 return (StatusCode::PRECONDITION_REQUIRED, "If-Match header required").into_response()
26 }
27 };
28 
29 let current = match repo.find(id).await {
30 Ok(Some(article)) => article,
31 Ok(None) => return StatusCode::NOT_FOUND.into_response(),
32 Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
33 };
34 
35 if current.version.to_string() != if_match {
36 return StatusCode::PRECONDITION_FAILED.into_response();
37 }
38 
39 match repo
40 .update_if_version(id, current.version, &payload.title, &payload.body)
41 .await
42 {
43 Ok(Some(updated)) => {
44 let etag = format!("\"{}\"", updated.version);
45 ([(header::ETAG, etag)], Json(updated)).into_response()
46 }
47 Ok(None) => StatusCode::PRECONDITION_FAILED.into_response(),
48 Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
49 }
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Conditional requests via If-Match let you detect and reject writes based on stale data.
  2. 2Comparing a version token before and during the update guards against races between the check and the write.
  3. 3Returning the new ETag on success lets clients chain further conditional updates safely.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Optimistic concurrency with ETags in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code