Extracting Data from Requests

warp provides a variety of filters to extract data from incoming HTTP requests, such as query parameters, headers, and the request body.

Query Parameters

The warp::query() filter deserializes the request's query string (e.g., ?foo=bar&baz=123) into a specified type. The type must implement serde::Deserialize.

Extracting to a HashMap

You can extract all query parameters into a HashMap for dynamic access.

use std::collections::HashMap;
use warp::Filter;

// Matches requests like /example1?key=value
let route = warp::path("example1")
    .and(warp::query::<HashMap<String, String>>())
    .map(|p: HashMap<String, String>| {
        match p.get("key") {
            Some(key) => format!("key = {}", key),
            None => "No 'key' param found.".to_string(),
        }
    });

Extracting to a Custom Struct

For more structured and type-safe data, define a struct and derive serde::Deserialize.

use serde_derive::Deserialize;
use warp::Filter;

#[derive(Deserialize)]
struct MyObject {
    key1: String,
    key2: u32,
}

// Matches requests like /example2?key1=value&key2=42
let route = warp::path("example2")
    .and(warp::query::<MyObject>())
    .map(|p: MyObject| {
        format!("key1 = {}, key2 = {}", p.key1, p.key2)
    });

Headers

The warp::header module provides filters for extracting request headers.

use std::net::SocketAddr;
use warp::Filter;

// Extract 'host' header as a SocketAddr
let host = warp::header::<SocketAddr>("host");

// Require 'accept' header to be exactly '*/*'
let accept_stars = warp::header::exact("accept", "*/*");

// Optionally extract the 'dnt' header
let dnt = warp::header::optional::<bool>("dnt");

let routes = host
    .and(accept_stars)
    .map(|addr: SocketAddr| format!("Accepting stars on {}", addr));

Request Body

The warp::body module contains filters to handle the request body.

JSON Body

To deserialize a JSON request body, use warp::body::json(). The target type must implement serde::Deserialize.

use serde_derive::Deserialize;
use warp::Filter;

#[derive(Deserialize)]
struct Employee {
    name: String,
    rate: u32,
}

let promote = warp::post()
    .and(warp::path("employees"))
    // Protect against large bodies
    .and(warp::body::content_length_limit(1024 * 16))
    .and(warp::body::json())
    .map(|mut employee: Employee| {
        employee.rate *= 2;
        warp::reply::json(&employee)
    });

Form Body (URL-Encoded)

For application/x-www-form-urlencoded bodies, use warp::body::form().

use std::collections::HashMap;
use warp::Filter;

let route = warp::post()
    .and(warp::body::form::<HashMap<String, String>>())
    .map(|map| /* ... */);

Multipart Form Data

For multipart/form-data, used for file uploads, warp provides warp::multipart::form(). This filter extracts a FormData object, which is a stream of Parts.

use bytes::BufMut;
use futures_util::TryStreamExt;
use warp::multipart::{FormData, Part};
use warp::Filter;

let upload = warp::multipart::form()
    .and_then(|form: FormData| async move {
        let parts: Vec<Part> = form.try_collect().await.map_err(|e| {
            eprintln!("form error: {}", e);
            warp::reject::reject()
        })?;

        // ... process parts ...

        Ok("Upload successful")
    });

This is just a high-level overview. For more details on handling streams from multipart forms, see the multipart.rs example.