Question
How can I make an HTTP request in Rust? I cannot find support for this in the standard library.
I only need to send a request and inspect the HTTP response status code; I do not need to parse the response body.
It would also be helpful to see how to safely URL-encode query parameters.
For example, the goal is something like:
// Pseudocode
let response = make_request("https://example.com/search?q=rust language");
println!("Status: {}", response.status());
Short Answer
By the end of this page, you will understand how HTTP requests are typically made in Rust, why the standard library does not include a full HTTP client, and how to use a crate such as reqwest to send requests, check status codes, and safely add URL-encoded query parameters.
Concept
Rust's standard library focuses on core building blocks such as strings, collections, file I/O, networking primitives, and concurrency. It does not provide a high-level HTTP client.
That means if you want to make HTTP requests in Rust, you usually use a community crate. The most common beginner-friendly choice is [reqwest], which provides a simple API for sending HTTP requests.
Why this matters
HTTP requests are used everywhere in real programs:
- calling APIs
- downloading files
- checking whether a service is online
- sending form data
- authenticating users
A good HTTP client should help you:
- build URLs safely
- send requests using methods like
GETandPOST - inspect status codes such as
200 OKor404 Not Found - handle network errors cleanly
Key idea
In Rust, the usual workflow is:
- Add an HTTP client crate to
Cargo.toml - Send a request
- Check the returned
Response - Read the status code or body if needed
For URL encoding, you should avoid manually concatenating strings when query values may contain spaces, &, ?, or other special characters. Instead, use helper methods that encode parameters correctly for you.
Mental Model
Think of Rust's standard library as a basic toolbox.
It gives you essentials like:
- a hammer
- a screwdriver
- measuring tape
But an HTTP client is more like a specialized power tool. It is extremely useful, but not part of the smallest core set of tools.
So when you need to talk to a website or API, you reach for an external crate like reqwest.
For query parameters, imagine writing an address on a package. If the address contains spaces or special symbols, you need to format it correctly so the delivery system understands it. URL encoding does that formatting for web addresses.
Syntax and Examples
The easiest way to make an HTTP request in Rust is with the reqwest crate.
Add the dependency
In Cargo.toml:
[dependencies]
reqwest = { version = "0.12", features = ["blocking"] }
The blocking feature is useful for simple scripts and beginner examples.
Simple GET request
use reqwest::blocking::get;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let response = get("https://httpbin.org/status/200")?;
println!("Status: {}", response.status());
Ok(())
}
What this does
get(...)sends a GET request- it returns a
Response response.status()gives the HTTP status code?passes errors upward if the request fails
Adding query parameters safely
Instead of building the URL manually, use .query(...):
use reqwest::blocking::Client;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new();
let response = client
.get("https://httpbin.org/get")
.query(&[("q", "rust language"), ("page", "1")])
.send()?;
println!("Status: {}", response.status());
Ok(())
}
Why .query(...) is better
It automatically URL-encodes values like:
- spaces
- punctuation
- symbols such as
&
For example, rust language becomes a safe query value in the final URL.
Manual URL encoding example
If you specifically need to encode values yourself, use the urlencoding crate.
In Cargo.toml:
[dependencies]
urlencoding = "2"
Example:
use urlencoding::encode;
fn main() {
let term = "rust language & web";
let encoded = encode(term);
println!("{}", encoded);
}
This prints an encoded string suitable for placing into a URL query.
Step by Step Execution
Consider this example:
use reqwest::blocking::Client;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new();
let response = client
.get("https://httpbin.org/get")
.query(&[("q", "rust language")])
.send()?;
println!("Status: {}", response.status());
Ok(())
}
Here is what happens step by step:
Client::new()creates an HTTP client..get("https://httpbin.org/get")prepares a GET request..query(&[("q", "rust language")])adds a query parameter.- Rust passes the key
q - Rust passes the value
rust language reqwestURL-encodes the value safely
- Rust passes the key
.send()?sends the request over the network.- If the network is down or the URL is invalid, an error is returned.
- Otherwise, you get a
Response.
response.status()reads the HTTP status code.println!prints something likeStatus: 200 OK.Ok(())ends the program successfully.
Important detail
An HTTP error like 404 Not Found is still usually a successful network request. That means:
- the request itself worked
- the server responded
- the status code indicates the result
So you often need to check response.status() explicitly.
Real World Use Cases
HTTP requests in Rust are common in many types of software.
API clients
A Rust service may call another API to fetch:
- user profiles
- payment status
- weather data
- shipping updates
Health checks
A monitoring script can send a request to a service endpoint and verify that it returns 200 OK.
Command-line tools
A CLI written in Rust might:
- test whether a URL is reachable
- verify a deployment endpoint
- query a web service
Data ingestion
A backend job can request data from a remote server, then process or store it.
Search and filtering
Applications often send query parameters such as:
?q=rust?page=2?sort=desc
Using a proper query builder avoids broken URLs and encoding bugs.
Real Codebase Usage
In real Rust codebases, developers usually avoid one-off string concatenation for URLs and instead use clients and helper methods.
Common patterns
Reuse a Client
Instead of calling a top-level get everywhere, many projects create a Client once and reuse it.
use reqwest::blocking::Client;
fn build_client() -> Client {
Client::new()
}
This keeps code organized and is often more efficient.
Check status explicitly
if response.status().is_success() {
println!("Request succeeded");
} else {
println!("Request failed with status: {}", response.status());
}
Guard clauses for errors
use reqwest::blocking::get;
use std::error::Error;
fn check_url(url: &str) -> Result<(), Box<dyn Error>> {
let response = get(url)?;
if !response.status().is_success() {
return Err(format!("Request failed: {}", response.status()).into());
}
Ok(())
}
Separate URL construction from request logic
This makes testing and maintenance easier.
fn search_url() -> &'static str {
"https://httpbin.org/get"
}
Use query helpers instead of manual formatting
client
.get(search_url())
.query(&[("q", "rust language"), ("limit", "10")])
.send()?;
This reduces encoding mistakes and makes code easier to read.
Common Mistakes
Beginners often run into a few common problems when making HTTP requests in Rust.
1. Expecting HTTP support in the standard library
Rust's standard library does not include a high-level HTTP client.
Incorrect idea
// This kind of API does not exist in std
// let response = std::http::get("https://example.com");
Fix
Add a crate like reqwest in Cargo.toml.
2. Manually building query strings unsafely
Problem
let term = "rust language & web";
let url = format!("https://example.com/search?q={}", term);
This can produce an invalid or misleading URL because special characters are not encoded.
Better
let response = client
.get("https://example.com/search")
.query(&[("q", "rust language & web")])
.send()?;
3. Confusing network errors with HTTP status errors
Problem
Some learners think 404 automatically becomes a Rust error.
Reality
- network failure: Rust error
- timeout: Rust error
- invalid URL: Rust error
404 Not Found: usually still a validResponse
You must inspect the status code.
4. Forgetting to enable the right feature
If you want blocking examples, the blocking feature must be enabled.
reqwest = { version = "0.12", features = ["blocking"] }
5. Ignoring the Result
Broken code
let response = reqwest::blocking::get("https://example.com");
println!("{:?}", response.status());
This fails because get(...) returns a Result<Response, Error>.
Fixed code
let response = reqwest::blocking::get("https://example.com")?;
println!("Status: {}", response.status());
6. Using string concatenation everywhere
Large codebases become harder to maintain if every URL is assembled by hand. Prefer helper functions, query builders, and constants.
Comparisons
Here are some useful comparisons related to making HTTP requests in Rust.
| Option | Best for | Pros | Cons |
|---|---|---|---|
std library only | Low-level networking | No extra dependencies | No high-level HTTP client |
reqwest::blocking | Simple scripts, beginner examples | Easy to read, straightforward | Blocks the current thread |
async reqwest | Async apps and servers | Works well in async systems | Slightly more setup |
| Manual URL string building | Very simple fixed URLs | Quick for tiny cases | Error-prone for query parameters |
.query(...) helper | Query parameters | Safe and readable | Requires using the client API |
get(...) vs Client::new().get(...)
| Approach | When to use | Example |
|---|---|---|
reqwest::blocking::get(...) | One simple request | Small scripts |
Client | Multiple requests, reusable setup | Real applications |
Manual encoding vs automatic encoding
| Approach | Recommendation | Reason |
|---|---|---|
| Manual encoding | Use only when necessary | Easy to make mistakes |
.query(...) | Preferred | Automatically encodes values correctly |
Cheat Sheet
[dependencies]
reqwest = { version = "0.12", features = ["blocking"] }
Simple request
let response = reqwest::blocking::get("https://example.com")?;
println!("{}", response.status());
Reusable client
let client = reqwest::blocking::Client::new();
let response = client.get("https://example.com").send()?;
Add query parameters safely
let response = client
.get("https://example.com/search")
.query(&[("q", "rust language"), ("page", "1")])
.send()?;
Check status
if response.status().is_success() {
println!("OK");
}
Remember
reqwestis not part of the standard libraryget(...)returnsResult<Response, Error>404is usually not a Rust error by itself- use
.query(...)instead of manual string concatenation - enable
blockingif using blocking examples
Optional manual encoding
urlencoding = "2"
let encoded = urlencoding::encode("rust language & web");
FAQ
Why doesn't Rust's standard library include HTTP requests?
Rust keeps the standard library relatively small and focused on core features. High-level HTTP support is usually provided by crates such as reqwest.
What crate should I use for HTTP requests in Rust?
For most beginners and many real projects, reqwest is the most common choice because it is ergonomic and well documented.
How do I check only the HTTP status code in Rust?
Send the request, get the Response, and call response.status().
How do I URL-encode query parameters in Rust?
The safest option is to use .query(...) with reqwest::Client, which encodes parameters for you.
Is 404 Not Found returned as a Rust error?
Usually no. A 404 is often a valid HTTP response, so you need to inspect the status code yourself.
Should I use blocking or async reqwest?
Use blocking for simple scripts and learning. Use async reqwest when working inside an async application.
Can I make a request without parsing the body?
Yes. You can send the request and inspect only response.status() without reading the response text.
Mini Project
Description
Build a small Rust command-line program that sends an HTTP GET request to a search endpoint, includes user-provided query parameters safely, and prints the HTTP status code. This demonstrates the most common beginner workflow: create a client, attach query parameters, send a request, and inspect the response.
Goal
Create a Rust program that sends a GET request with encoded query parameters and reports whether the request succeeded based on the HTTP status code.
Requirements
- Create a Rust project that uses
reqwestwith theblockingfeature. - Send a GET request to
https://httpbin.org/get. - Add at least two query parameters using a safe query builder.
- Print the full HTTP status code.
- Print a success or failure message based on the status.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.