If you have ever used have every made a request using rust, you probably have used the reqwest crate.
This crate is widely used to make HTTP requests in Rust.
In this article, we will discuss three impressive additions to it.
Namely: JSON handling, multipart forms, and streaming capabilities
JSON: Seamless Serialization
Due to Rust’s intense type system, JSON serialization is not as simple as it sounds.
Without this feature flag enabled to make JSON requests with Rust, you would have to declare a struct representing the image of the expected data from the request and parse the response text manually using serde_json
.
However, with this new feature enabled, you can just be called the .json
method.
Here is how it works: Reqwest integrates with serde
to automatically convert Rust structs to JSON requests and responses.
Example: API Interaction
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Post {
title: String,
content: String,
}
async fn create_post() -> Result<Post, reqwest::Error> {
let client = reqwest::Client::new();
let new_post = Post {
title: "Hello Reqwest".into(),
content: "Exploring JSON features".into(),
};
let response = client.post("https://api.example.com/posts")
.json(&new_post)
.send()
.await?
.json()
.await?;
Ok(response)
}
2. Multipart: File Uploads
The multipart
feature simplifies file uploads and complex form submissions using MIME multipart/form-data
.
With this new interactive API, you can build multi-part forms in your requests, this is especially cool since some API routes only accept multi-part requests.
Here is an example of using this flag.
use reqwest::multipart;
async fn upload_file() -> Result<(), reqwest::Error> {
let form = multipart::Form::new()
.text("title", "My File")
.part("file",
multipart::Part::file("photo.jpg")?
.mime_str("image/jpeg")?
);
client.post("https://uploads.example.com")
.multipart(form)
.send()
.await?;
Ok(())
}
3. Streams: Handling Large Data Efficiently
How much RAM do you have?
You see when downloading large files from a remote source, say a 12 GB file from an API; sooner or later you would run into a problem — if your system has less RAM than your file — as you download the data you would eventually run out of memory.
Now the obvious solution to this problem would be streaming this data and and saving it into long-term storage IRL, well here is how to stream data with the reqwest library.
The stream
feature enables memory-efficient processing of large payloads by working with data in chunks.
Example: Streaming Download
use futures_util::StreamExt;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
async fn download_large_file() -> Result<(), reqwest::Error> {
let mut stream = client.get("https://large-files.example.com/video.mp4")
.send()
.await?
.bytes_stream();
let mut file = File::create("video.mp4").await?;
while let Some(chunk) = stream.next().await {
file.write_all(&chunk?).await?;
}
Ok(())
}
Enabling Features
These features are not added to the crate by default, as you may never have to use them. So to use them, make sure to enable them by adding these lines to your cargo.toml file.
Add to your Cargo.toml
:
[dependencies]
reqwest = { version = "0.11", features = ["json", "multipart", "stream"] }
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
or if adding these dependencies through the CLI, remember to pass them into the features flag.
cargo add crate --features feature_one feature_two
Glossary and Extra Context!
These are some features I use in my everyday usage of reqwest, feel free to comment on which was the best. To learn more about the reqwest crate, please read the docs here.
I am hoping you have learned a few more tricks, you rock !!!
To learn more about backend engineering , you might want to check out this course.