Handling Parameters
Path and Query variables.
Learning Objectives
- Extract variables from URLs
##Reading data from the URL
Real APIs need input: which user, which page, what search term. Actix Web gives you extractors, which are function parameters that pull data out of the request and convert it to Rust types before your handler runs.
#Path parameters
A path parameter is a variable part of the URL, such as /users/42. Mark it with braces in the route and read it with web::Path:
use actix_web::{get, web, App, HttpServer, Responder};
#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
let id = path.into_inner();
format!("User #{id}")
}If the client calls /users/abc, Actix cannot parse abc as a u32, so it answers 404 Not Found automatically. Your handler never runs with bad data.
For several parameters use a tuple, and keep them in the same order as the route:
#[get("/users/{user_id}/posts/{post_id}")]
async fn get_post(path: web::Path<(u32, u32)>) -> impl Responder {
let (user_id, post_id) = path.into_inner();
format!("User {user_id}, post {post_id}")
}#Query parameters
Query strings like /search?q=rust&page=2 are read with web::Query and a struct:
use serde::Deserialize;
#[derive(Deserialize)]
struct SearchParams {
q: String,
page: Option<u32>,
}
#[get("/search")]
async fn search(params: web::Query<SearchParams>) -> impl Responder {
let page = params.page.unwrap_or(1);
format!("Searching for {} on page {}", params.q, page)
}Fields typed as Option<T> are optional. A missing required field such as q makes Actix return 400 Bad Request with an explanation.
#Why extractors are great
- Parsing and validation happen before your code, so handlers stay short.
- The types document the API: you can see exactly what each route accepts.
- You can combine them freely: path, query, JSON body and shared state can all appear in one handler.
#Default values
Use serde defaults to avoid Option unwrapping:
fn default_page() -> u32 { 1 }
#[derive(Deserialize)]
struct Paging {
#[serde(default = "default_page")]
page: u32,
}Now page is always a plain u32, and /items without a query string works as page 1.
Interactive Code Inspector
Select any highlighted line of code below to deeply inspect its mechanics, understand why it exists, and what happens if you change it.
"What If?" Experiment
Learning by doing. Modify the code to see what happens.
See extraction failure in action.
Request /users/abc instead of /users/42.
Actix returns 404 and the handler is never called.
Explanation: The path segment cannot be parsed as u32, so the extractor fails and Actix answers on your behalf.
Common Mistakes
Anticipate and avoid these frequent pitfalls when working with this concept.
Path tuple in the wrong order
Tuple elements are matched to placeholders by position, not by name.
Explanation: The first element is the first placeholder in the route. Use a struct with named fields if the order is hard to remember.
Forgetting Deserialize on the query struct
web::Query<T> needs T: Deserialize to decode the query string.
Explanation: Without the derive the compiler reports that the trait bound Deserialize is not satisfied.
Practical Exercise
Build a paginated listing
TaskCreate GET /items that accepts optional page and limit query parameters and returns a text summary.
Requirements
- Define a Paging struct with page and limit
- page defaults to 1 and limit defaults to 10
- Return "page X, limit Y"
Need a hint?
Try solving the exercise in your local environment first. Once you have a solution, or if you get completely stuck, reveal the answer.
Real-World Application
List endpoints in production almost always take page, limit, sort and filter query parameters, while detail endpoints identify the record with a path parameter. Typed extractors keep that logic short and consistent.
Key Takeaways
- web::Path<T> reads values from {placeholders} in the route.
- web::Query<T> reads the query string into a struct that derives Deserialize.
- Option fields are optional; missing required fields give a 400 response.
- Failed extraction stops the request before your handler runs.
Finished reading?
Mark this lesson as done to track your progress and earn XP.