How to use http crate in Rust HTTP types

The `http` crate provides the foundational, platform-agnostic types (like `Request`, `Response`, `HeaderMap`, and `Method`) used by the Rust ecosystem, but it does not include an HTTP client or server implementation itself.

The http crate provides the foundational, platform-agnostic types (like Request, Response, HeaderMap, and Method) used by the Rust ecosystem, but it does not include an HTTP client or server implementation itself. You use it to construct, parse, and manipulate HTTP messages in memory, typically as a dependency for building custom clients, servers, or middleware that rely on these standard types.

Here is a practical example of constructing a Request with headers and a body:

use http::{Request, Response, StatusCode, header::{HeaderName, HeaderValue, CONTENT_TYPE}};
use http::Method;
use std::io::Cursor;

fn create_request() -> Result<Request<Vec<u8>>, http::Error> {
    // Create a body from a string
    let body = b"Hello, world!";
    
    // Build the request
    let mut req = Request::builder()
        .method(Method::POST)
        .uri("https://api.example.com/data")
        .header(CONTENT_TYPE, "application/json")
        .body(body.to_vec())?;

    // Access and modify headers
    if let Some(content_type) = req.headers().get(CONTENT_TYPE) {
        println!("Content-Type: {}", content_type.to_str().unwrap());
    }

    Ok(req)
}

fn create_response() -> Response<String> {
    Response::builder()
        .status(StatusCode::OK)
        .body("Success".to_string())
        .unwrap()
}

In this snippet, Request::builder() is the standard pattern for creating messages. Note that body is generic; here we use Vec<u8>, but it could be a String or a custom stream type. The header module provides constants like CONTENT_TYPE to avoid string typos.

To parse a raw HTTP request string into these types, you would typically use a parser like httparse or a higher-level library, as http itself focuses on the data structures. However, if you are working with a client like reqwest or a server like hyper, they automatically convert their internal types to/from http crate types. For instance, reqwest::Request can be converted into http::Request using the TryInto trait if you need to inspect or modify the raw message before sending:

use reqwest::Client;
use http::Request;

async fn inspect_and_send() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();
    
    // Create a reqwest request
    let req = client.post("https://api.example.com")
        .json(&serde_json::json!({"key": "value"}))
        .build()?;

    // Convert to http::Request for inspection
    let http_req: Request<Vec<u8>> = req.try_into()?;
    
    println!("Method: {}", http_req.method());
    println!("URI: {}", http_req.uri());

    // Note: You usually send the original reqwest request, 
    // or convert back if the library supports it.
    Ok(())
}

Remember that http::Request and http::Response are just data containers. They do not handle network I/O, DNS resolution, or connection pooling. You must pair them with a runtime (like tokio) and a specific client/server library (like reqwest, hyper, or actix-web) to actually perform network operations.