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