rust 55 lines · 10 steps

Streaming multipart uploads in Axum

An Axum handler streams each multipart field to a temp file and returns JSON metadata for every saved upload.

Explained by highlit
1use axum::{extract::Multipart, http::StatusCode, Json};
2use serde::Serialize;
3use tokio::io::AsyncWriteExt;
4use uuid::Uuid;
5 
6#[derive(Serialize)]
7pub struct UploadedFile {
8 id: Uuid,
9 original_name: String,
10 content_type: String,
11 bytes: usize,
12}
13 
14pub async fn upload(mut multipart: Multipart) -> Result<Json<Vec<UploadedFile>>, (StatusCode, String)> {
15 let mut uploaded = Vec::new();
16 
17 while let Some(mut field) = multipart
18 .next_field()
19 .await
20 .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
21 {
22 if field.name() != Some("files") {
23 continue;
24 }
25 
26 let id = Uuid::new_v4();
27 let original_name = field.file_name().unwrap_or("unnamed").to_owned();
28 let content_type = field
29 .content_type()
30 .unwrap_or("application/octet-stream")
31 .to_owned();
32 
33 let path = std::env::temp_dir().join(id.to_string());
34 let mut file = tokio::fs::File::create(&path)
35 .await
36 .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
37 
38 let mut bytes = 0usize;
39 while let Some(chunk) = field
40 .chunk()
41 .await
42 .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
43 {
44 bytes += chunk.len();
45 file.write_all(&chunk)
46 .await
47 .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
48 }
49 
50 file.flush().await.ok();
51 uploaded.push(UploadedFile { id, original_name, content_type, bytes });
52 }
53 
54 Ok(Json(uploaded))
55}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Streaming file fields chunk by chunk keeps memory flat regardless of upload size.
  2. 2Mapping every fallible await into a (StatusCode, String) gives the handler uniform, client-friendly error responses.
  3. 3Generating a UUID filename avoids collisions and untrusted-path issues when persisting user uploads.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Streaming multipart uploads in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code