In the fast-paced world of web development, crafting an efficient multipart file upload server is a skill worth mastering.
This guide explores the fusion of Rust’s performance and safety with the asynchronous prowess of Tokio, along with the ergonomic web framework, Axum. Whether you’re a seasoned Rust developer or a newcomer, this article takes you through the creation of a multipart file upload server step by step.
From setting up your Rust environment to harnessing Tokio’s asynchronous power and leveraging Axum’s elegant syntax, you’ll gain the insights and tools needed to optimize file uploads for modern web applications. Join us on this journey to unlock the potential of Rust, Tokio, and Axum, enabling you to build high-performance and scalable file upload solutions effortlessly.
Setup -
Let’s start by creating our project workspace with Cargo!
|
|
Next, we’re going to need tokio
and axum
in order to host our server and control routing.
Let’s add the following lines to our Cargo.toml:
|
|
Guide -
For now, you don’t need to understand what a multipart is or why we’re enabling it. Let’s first focus on creating a basic Hello World router with axum
.
Let’s replace /src/main.rs
with the following code:
|
|
After starting your server with cargo run
and navigating to localhost:3000
in your browser, you should be met with “Hello, World!”.
Congrats! That’s the most basic form of server with axum
, but we’re only serving a string right now. Let’s instead serve /public/index.html
.
Create a new folder in your root workspace and title it public. Create an index.html file within with the following contents:
|
|
But how do we serve this? Well, axum
makes this easy. All we have to do is replace our Hello, World! code with an HTML response. axum
does this for us, if we ask it nicely, of course.
|
|
After starting your server back up with cargo run
, navigating to localhost:3000
now shows Hello, HTML!. Nice work!
Now, let’s create a file upload form to let us drop our files to the server. Let’s replace our Hello, HTML! code with the following to do so:
|
|
If we restart our server, we now have a very basic file drop page.
Now, how do we implement the backend?
This form will submit what’s called a multipart request. This is a type of HTTP request that contains multiple types of data, often used for files. For instance, if you wished to submit a file (raw bytes) and its metadata (text), you have conflicting data types. Multipart requests solve this by splitting them.
Let’s implement a reciever for it!
First, we’ll need to create a route for our incoming POST request. We can do this by chaining a .post(upload)
onto our existing .get(index)
.
|
|
Now, if we restart our server and upload a file via localhost:3000
…voila! We get Got file! in our output.
Let’s break down why.
Our upload axum route function accepts a Multipart input, which we then iterate through each field of. We chose to ignore any field that’s not explicitly a file upload.
Nice! Now, let’s extract the bytes and save the incoming file.
We’ll start by creating a new folder in our root directory, /files
.
Next, let’s extract the bytes and save them to a file in said directory.
|
|
Start your server back up one last time, and upload a file!
Congratulations, you should now see whatever file you uploaded in /files
.
Result
Our final /src/main.rs
should look something like this.
|
|
Outro -
Hopefully you found this article informative or helpful. If you did, follow my GitHub!
I often write these articles after struggling to find good documentation on a concept. That means there’s often a large-scale project on there related to this article, if you’d like to see it in practice!