### Configure SOCKS5 Proxy with ureq Source: https://github.com/algesten/ureq/blob/main/README.md This example demonstrates how to set up a SOCKS5 proxy for an Agent. Verify the SOCKS5 URL format. ```rust use ureq::{Agent, Proxy}; // Configure a SOCKS proxy. let proxy = Proxy::new("socks5://user:password@cool.proxy:9090")?; let agent: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); // This is proxied. let resp = agent.get("http://cool.server").call()?; ``` -------------------------------- ### Basic HTTP GET Request in Rust Source: https://github.com/algesten/ureq/blob/main/README.md Demonstrates a simple GET request to a URL, setting a header, and reading the response body as a string. Requires basic ureq setup. ```rust let body: String = ureq::get("http://example.com") .header("Example-Header", "header value") .call()? .body_mut() .read_to_string()?; ``` -------------------------------- ### Install ureq with Features Source: https://context7.com/algesten/ureq/llms.txt Add ureq to your Cargo.toml. Default includes rustls and gzip. Enable features like json, cookies, and socks-proxy for extended functionality. ```toml # Default: rustls + gzip enabled ureq = "3" # With extra features ureq = { version = "3", features = ["json", "cookies", "socks-proxy", "charset", "brotli", "multipart"] } ``` -------------------------------- ### Simple GET Request with ureq Source: https://context7.com/algesten/ureq/llms.txt Make a simple GET request and read the response body as a string. Ensure to handle potential errors during the request or body reading. ```rust use ureq::Error; // Simple GET — read response as string let body: String = ureq::get("https://httpbin.org/get") .header("Accept", "application/json") .call()? .body_mut() .read_to_string()?; // POST with raw bytes body let resp = ureq::post("https://httpbin.org/post") .header("Content-Type", "application/octet-stream") .send(&[0u8; 64])?; assert_eq!(resp.status(), 200); // DELETE with query parameters ureq::delete("https://httpbin.org/delete") .query("id", "42") .query("confirm", "true") .call()?; // PATCH with string body ureq::patch("https://httpbin.org/patch") .content_type("text/plain") .send("hello world")?; // PUT with a File (sends Content-Length automatically) let file = std::fs::File::open("data.bin")?; ureq::put("https://httpbin.org/put") .send(file)?; // Error handling — status codes 4xx/5xx are Err by default match ureq::get("https://httpbin.org/status/404").call() { Ok(_) => println!("ok"), Err(Error::StatusCode(code)) => println!("server returned {}", code), Err(e) => println!("transport/io error: {}", e), } # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Basic HTTPS Request with Rustls Source: https://github.com/algesten/ureq/blob/main/README.md Demonstrates a simple GET request to an HTTPS URL using the default rustls TLS implementation. Ensure the 'rustls' feature is enabled. ```rust // This uses rustls ureq::get("https://www.google.com/").call().unwrap(); ``` -------------------------------- ### Force Send Body on GET/DELETE in ureq Source: https://context7.com/algesten/ureq/llms.txt Use `.force_send_body()` as an escape hatch to send a request body with methods like GET or DELETE, which typically do not have bodies, for compatibility with certain APIs. ```rust use ureq::Agent; let agent = ureq::agent(); // --- Force send body on a GET (escape hatch for broken APIs) --- let resp = ureq::delete("https://httpbin.org/delete") .force_send_body() .send("body on DELETE")?; ``` -------------------------------- ### Configure TLS Backends in ureq Source: https://context7.com/algesten/ureq/llms.txt Demonstrates setting up ureq with different TLS backends (rustls, native-tls) and root certificate configurations. Use `RootCerts::PlatformVerifier` to leverage the OS's certificate store. Disabling verification is for testing only. ```rust use ureq::Agent; use ureq::tls::{TlsConfig, TlsProvider, RootCerts}; // Default: rustls with bundled Mozilla root certs (webpki-roots) ureq::get("https://www.google.com/").call()?; // Use OS platform certificate verifier (feature: platform-verifier) let agent = Agent::config_builder() .tls_config( TlsConfig::builder() .root_certs(RootCerts::PlatformVerifier) .build() ) .build() .new_agent(); agent.get("https://www.google.com/").call()?; // native-tls backend (feature: native-tls) use ureq::config::Config; let agent = Config::builder() .tls_config( TlsConfig::builder() .provider(TlsProvider::NativeTls) .build() ) .build() .new_agent(); agent.get("https://www.google.com/").call()?; // Disable certificate verification (DANGEROUS — testing only) let agent = Agent::config_builder() .tls_config( TlsConfig::builder() .disable_verification(true) .build() ) .build() .new_agent(); # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Agent Configuration with ConfigBuilder Source: https://context7.com/algesten/ureq/llms.txt Demonstrates how to use `ConfigBuilder` to fluently configure an `Agent`, setting options like timeouts, TLS, IP family, and connection pool sizes. ```APIDOC ## `Agent::config_builder` / `Config::builder` — Agent configuration `ConfigBuilder` provides a fluent API for configuring all aspects of the HTTP client: timeouts, TLS, proxies, redirects, connection pool sizes, and more. The built `Config` can be converted directly into an `Agent`. ```rust use ureq::{Agent, config::IpFamily}; use std::time::Duration; let agent: Agent = Agent::config_builder() // Treat 4xx/5xx as errors (default: true) .http_status_as_error(true) // Reject non-HTTPS requests .https_only(false) // Only use IPv4 .ip_family(IpFamily::Ipv4Only) // End-to-end timeout for entire call including body .timeout_global(Some(Duration::from_secs(30))) // Timeout for DNS resolution .timeout_resolve(Some(Duration::from_secs(5))) // Timeout for TCP + TLS connect .timeout_connect(Some(Duration::from_secs(5))) // Timeout for reading response body .timeout_recv_body(Some(Duration::from_secs(20))) // Max redirects to follow .max_redirects(10) // Pool settings .max_idle_connections(20) .max_idle_connections_per_host(5) .max_idle_age(Duration::from_secs(30)) .build() .into(); agent.get("https://httpbin.org/get").call()?; # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Configure HTTP CONNECT Proxy with Credentials Source: https://context7.com/algesten/ureq/llms.txt Sets up an HTTP CONNECT proxy with username and password authentication using the `Agent` configuration. ```rust use ureq::{Agent, Proxy}; // HTTP CONNECT proxy with credentials let proxy = Proxy::new("http://user:password@proxy.corp.example.com:8080")?; let agent: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); let resp = agent.get("https://api.example.com/data").call()?; ``` -------------------------------- ### Configure SOCKS5 Proxy Source: https://context7.com/algesten/ureq/llms.txt Sets up a SOCKS5 proxy. Note that this requires the `socks-proxy` feature to be enabled. ```rust // SOCKS5 proxy (requires feature: socks-proxy) let socks_proxy = Proxy::new("socks5://user:pass@socks.example.com:1080")?; let agent2: Agent = Agent::config_builder() .proxy(Some(socks_proxy)) .build() .into(); ``` -------------------------------- ### Configure HTTP Proxy with ureq Source: https://github.com/algesten/ureq/blob/main/README.md Use this snippet to configure an HTTP connect proxy for an Agent. Ensure the proxy URL is correctly formatted. ```rust use ureq::{Agent, Proxy}; // Configure an http connect proxy. let proxy = Proxy::new("http://user:password@cool.proxy:9090")?; let agent: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); // This is proxied. let resp = agent.get("http://cool.server").call()?; ``` -------------------------------- ### Agent::run Source: https://context7.com/algesten/ureq/llms.txt Executes an `http::Request` directly, built using the `http` crate's builder API, enabling direct use of standard `http` ecosystem types. ```APIDOC ## `Agent::run` — Execute `http::Request` directly `Agent::run` accepts an `http::Request` built using the `http` crate's builder API, enabling direct use of standard `http` ecosystem types. ```rust use ureq::{Agent, http}; let agent = Agent::new_with_defaults(); // Standard GET via http crate builder let request = http::Request::get("https://httpbin.org/get") .header("Accept", "application/json") .body(())?; let body = agent.run(request)? .body_mut() .read_to_string()?; // Non-standard HTTP methods (e.g., WebDAV PROPFIND) let request = http::Request::builder() .method("PROPFIND") .uri("https://dav.example.com/files/") .body("")?; let resp = Agent::config_builder() .allow_non_standard_methods(true) .build() .new_agent() .run(request)?; # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Creating and Using an Agent for HTTP Requests in Rust Source: https://github.com/algesten/ureq/blob/main/README.md Shows how to create a ureq Agent with a global timeout configuration. The Agent manages connection pools and cookie stores, allowing for efficient reuse of connections across multiple requests. ```rust use ureq::Agent; use std::time::Duration; let mut config = Agent::config_builder() .timeout_global(Some(Duration::from_secs(5))) .build(); let agent: Agent = config.into(); let body: String = agent.get("http://example.com/page") .call()? .body_mut() .read_to_string()?; // Reuses the connection from previous request. let response: String = agent.put("http://example.com/upload") .header("Authorization", "example-token") .send("some body data")? .body_mut() .read_to_string()?; ``` -------------------------------- ### Check Outdated Dependencies with cargo-outdated Source: https://github.com/algesten/ureq/blob/main/RELEASE.txt Use `cargo outdated --depth=1` to scan for dependencies that can be updated. The initial `cargo update` ensures your checkout uses the latest allowed dependencies. ```bash cargo update cargo outdated --depth=1 ``` -------------------------------- ### RequestBuilder for Fluent Request Construction Source: https://context7.com/algesten/ureq/llms.txt Illustrates how to use `RequestBuilder` to construct HTTP requests, including setting headers, query parameters, and overriding per-request configurations. ```APIDOC ## `RequestBuilder` — Fluent request construction `RequestBuilder` wraps `http::request::Builder` and adds `.call()`, `.send()`, `.send_json()`, `.send_form()`, query helpers, and per-request config overrides. The typestate (`WithBody` / `WithoutBody`) enforces at compile time which methods accept a body. ```rust use ureq::Agent; let agent = ureq::agent(); // --- Headers --- let resp = agent.get("https://httpbin.org/headers") .header("X-Custom", "value") .header("Authorization", "Bearer token123") .call()?; // --- Query parameters (auto percent-encoded) --- let resp = agent.get("https://httpbin.org/get") .query("search", "hello world") // encodes to search=hello%20world .query("page", "1") .call()?; // --- Multiple query pairs at once --- let params = [("format", "json"), ("limit", "100")]; let resp = agent.get("https://httpbin.org/get") .query_pairs(params) .call()?; // --- Per-request config override --- let result = agent.get("https://httpbin.org/status/404") .config() .http_status_as_error(false) // don't error on 404 .build() .call()?; assert_eq!(result.status(), 404); // --- Force send body on a GET (escape hatch for broken APIs) --- let resp = ureq::delete("https://httpbin.org/delete") .force_send_body() .send("body on DELETE")?; # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Configure Agent with Native TLS Source: https://github.com/algesten/ureq/blob/main/README.md Shows how to configure ureq to use the native-tls backend for TLS connections. This requires enabling the 'native-tls' feature and explicitly setting the TLS provider on the agent. ```rust use ureq::config::Config; use ureq::tls::{TlsConfig, TlsProvider}; let mut config = Config::builder() .tls_config( TlsConfig::builder() // requires the native-tls feature .provider(TlsProvider::NativeTls) .build() ) .build(); let agent = config.new_agent(); agent.get("https://www.google.com/").call().unwrap(); ``` -------------------------------- ### Proxy Builder with NO_PROXY Exceptions Source: https://context7.com/algesten/ureq/llms.txt Configures a proxy using the builder pattern, specifying NO_PROXY exceptions for specific hosts and domains. ```rust // Builder API with NO_PROXY exceptions use ureq::ProxyProtocol; let proxy = Proxy::builder(ProxyProtocol::Http) .host("proxy.corp.com") .port(3128) .no_proxy("localhost") .no_proxy("*.internal.corp.com") .no_proxy(".dev") .build()?; let agent3: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Publish Release to crates.io Source: https://github.com/algesten/ureq/blob/main/RELEASE.txt Publish the new version of the crate to the crates.io registry. Ensure all previous steps, including CI checks, have passed. ```bash cargo publish ``` -------------------------------- ### Execute http::Request directly with Agent::run Source: https://context7.com/algesten/ureq/llms.txt The `Agent::run` method accepts an `http::Request` built using the `http` crate's builder API, allowing direct use of standard `http` ecosystem types. This enables constructing requests with custom methods and bodies. ```rust use ureq::{Agent, http}; let agent = Agent::new_with_defaults(); // Standard GET via http crate builder let request = http::Request::get("https://httpbin.org/get") .header("Accept", "application/json") .body(()?)?; let body = agent.run(request)? .body_mut() .read_to_string()?; ``` ```rust // Non-standard HTTP methods (e.g., WebDAV PROPFIND) let request = http::Request::builder() .method("PROPFIND") .uri("https://dav.example.com/files/") .body("")?; let resp = Agent::config_builder() .allow_non_standard_methods(true) .build() .new_agent() .run(request)?; ``` -------------------------------- ### Configure ureq Agent with ConfigBuilder Source: https://context7.com/algesten/ureq/llms.txt Use ConfigBuilder for a fluent API to set timeouts, TLS settings, IP family, redirects, and connection pool sizes. The built Config can be converted into an Agent. ```rust use ureq::{Agent, config::IpFamily}; use std::time::Duration; let agent: Agent = Agent::config_builder() // Treat 4xx/5xx as errors (default: true) .http_status_as_error(true) // Reject non-HTTPS requests .https_only(false) // Only use IPv4 .ip_family(IpFamily::Ipv4Only) // End-to-end timeout for entire call including body .timeout_global(Some(Duration::from_secs(30))) // Timeout for DNS resolution .timeout_resolve(Some(Duration::from_secs(5))) // Timeout for TCP + TLS connect .timeout_connect(Some(Duration::from_secs(5))) // Timeout for reading response body .timeout_recv_body(Some(Duration::from_secs(20))) // Max redirects to follow .max_redirects(10) // Pool settings .max_idle_connections(20) .max_idle_connections_per_host(5) .max_idle_age(Duration::from_secs(30)) .build() .into(); agent.get("https://httpbin.org/get").call()?; # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Agent for Reusable HTTP Client Source: https://context7.com/algesten/ureq/llms.txt Create an Agent for connection pooling and shared state. Configure timeouts, redirects, and user agent. Cloned agents share the same pool. ```rust use ureq::Agent; use std::time::Duration; // Build agent with custom config let agent: Agent = Agent::config_builder() .timeout_global(Some(Duration::from_secs(10))) .timeout_connect(Some(Duration::from_secs(3))) .max_redirects(5) .user_agent("my-app/1.0") .build() .into(); // Connection is reused across requests to the same host let page1 = agent.get("https://httpbin.org/get") .call()? .body_mut() .read_to_string()?; let page2 = agent.post("https://httpbin.org/post") .send("some data")? .body_mut() .read_to_string()?; // Clone shares the connection pool — useful for multi-threaded programs let agent2 = agent.clone(); std::thread::spawn(move || { agent2.get("https://httpbin.org/get").call().ok(); }); # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Implement Request/Response Middleware in ureq Source: https://context7.com/algesten/ureq/llms.txt Shows how to use the `Middleware` trait or a simple function to intercept requests and responses. Middleware can add headers or track request counts. Multiple middleware are chained and configured at the `Agent` level. ```rust use std::sync::{Arc, atomic::{AtomicU64, Ordering}}; use ureq::{Agent, Body, SendBody, config::Config}; use ureq::middleware::{Middleware, MiddlewareNext}; use ureq::http::{Request, Response, header::HeaderValue}; // Simple function middleware — adds an auth header to every request fn add_auth(mut req: Request, next: MiddlewareNext) -> Result, ureq::Error> { req.headers_mut() .insert("Authorization", HeaderValue::from_static("Bearer secret-token")); next.handle(req) } // Stateful middleware — count requests with an atomic counter struct RequestCounter(Arc); impl Middleware for RequestCounter { fn handle(&self, req: Request, next: MiddlewareNext) -> Result, ureq::Error> { self.0.fetch_add(1, Ordering::Relaxed); next.handle(req) } } let counter = Arc::new(AtomicU64::new(0)); let agent: Agent = Config::builder() .middleware(add_auth) .middleware(RequestCounter(counter.clone())) .build() .into(); agent.get("https://httpbin.org/headers").call()?; agent.get("https://httpbin.org/get").call()?; assert_eq!(counter.load(Ordering::Relaxed), 2); # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### JSON Support for Request and Response Bodies Source: https://context7.com/algesten/ureq/llms.txt Shows how to send JSON request bodies and deserialize JSON responses using `serde_json` when the `json` feature is enabled. ```APIDOC ## `RequestBuilder::send_json` / `Body::read_json` — JSON support (feature: `json`) When the `json` feature is enabled, ureq integrates with `serde_json` for serializing request bodies and deserializing response bodies. The `Content-Type: application/json` header is set automatically. ```rust use serde::{Deserialize, Serialize}; #[derive(Serialize)] struct CreateUser { name: String, email: String, } #[derive(Deserialize, Debug)] struct UserResponse { id: u64, name: String, } // Send JSON and read JSON response let new_user = CreateUser { name: "Alice".to_string(), email: "alice@example.com".to_string(), }; let user: UserResponse = ureq::post("https://httpbin.org/post") .send_json(&new_user)? .body_mut() .read_json::()?; // Using serde_json::Value for dynamic JSON use serde_json::{json, Value}; let payload = json!({ "query": "select * from users", "limit": 10 }); let result: Value = ureq::post("https://httpbin.org/post") .send_json(&payload)? .body_mut() .read_json()?; println!("json field: {}", result["json"]); # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Configure Platform TLS Verifier in ureq Source: https://github.com/algesten/ureq/blob/main/README.md Use the platform verifier to access native OS certificate checking. This requires enabling the 'platform-verifier' feature flag and configuring the agent's TLS settings. ```rust use ureq::Agent; use ureq::tls::{TlsConfig, RootCerts}; let agent = Agent::config_builder() .tls_config( TlsConfig::builder() .root_certs(RootCerts::PlatformVerifier) .build() ) .build() .new_agent(); let response = agent.get("https://httpbin.org/get").call()?; ``` -------------------------------- ### Proxy Support Source: https://context7.com/algesten/ureq/llms.txt ureq provides comprehensive support for HTTP and SOCKS proxies, including authentication and automatic detection from environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY`). Proxy settings are configured on an `Agent`. ```APIDOC ## Proxy Support ureq supports HTTP CONNECT, HTTPS CONNECT, SOCKS4, SOCKS4A, SOCKS5, and SOCKS5h proxies. Proxy settings are configured on an `Agent`. The default `Agent` automatically reads `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, and `NO_PROXY` environment variables. ```rust use ureq::{Agent, Proxy}; // HTTP CONNECT proxy with credentials let proxy = Proxy::new("http://user:password@proxy.corp.example.com:8080")?; let agent: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); let resp = agent.get("https://api.example.com/data").call()?; // SOCKS5 proxy (requires feature: socks-proxy) let socks_proxy = Proxy::new("socks5://user:pass@socks.example.com:1080")?; let agent2: Agent = Agent::config_builder() .proxy(Some(socks_proxy)) .build() .into(); // Builder API with NO_PROXY exceptions use ureq::ProxyProtocol; let proxy = Proxy::builder(ProxyProtocol::Http) .host("proxy.corp.com") .port(3128) .no_proxy("localhost") .no_proxy("*.internal.corp.com") .no_proxy(".dev") .build()?; let agent3: Agent = Agent::config_builder() .proxy(Some(proxy)) .build() .into(); # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Handling HTTP Status Code Errors in Rust with Ureq Source: https://github.com/algesten/ureq/blob/main/README.md Demonstrates how to handle errors returned by ureq, specifically distinguishing between HTTP status code errors (4xx, 5xx) and other I/O or transport errors. The default behavior is to treat non-2xx status codes as errors. ```rust use ureq::Error; match ureq::get("http://mypage.example.com/").call() { Ok(response) => { /* it worked */}, Err(Error::StatusCode(code)) => { /* the server returned an unexpected status code (such as 400, 500 etc) */ } Err(_) => { /* some kind of io/transport/etc error */ } } ``` -------------------------------- ### JSON Request and Response Handling in Rust with Ureq Source: https://github.com/algesten/ureq/blob/main/README.md Illustrates sending and receiving JSON data using ureq. This requires the 'json' feature to be enabled. It defines serializable and deserializable structs for request and response bodies. ```rust use serde::{Serialize, Deserialize}; #[derive(Serialize)] struct MySendBody { thing: String, } #[derive(Deserialize)] struct MyRecvBody { other: String, } let send_body = MySendBody { thing: "yo".to_string() }; // Requires the `json` feature enabled. let recv_body = ureq::post("http://example.com/post/ingest") .header("X-My-Header", "Secret") .send_json(&send_body)? .body_mut() .read_json::()?; ``` -------------------------------- ### Agent — Reusable HTTP client with connection pooling Source: https://context7.com/algesten/ureq/llms.txt The `Agent` struct provides a reusable HTTP client with features like connection pooling, cookie persistence, and shared configuration. It is efficiently cloneable, making it suitable for multi-threaded applications. ```APIDOC ## Agent — Reusable HTTP client with connection pooling ### Description `Agent` holds a connection pool, optional cookie jar, and a shared `Config`. It is cheaply cloneable (backed by `Arc`); all clones share the same pool and state. Use an `Agent` when you need connection reuse, cookie handling, or a custom configuration applied to all requests. ### Method GET, POST, PUT, DELETE, PATCH (via Agent instance) ### Endpoint `https://httpbin.org/get` `https://httpbin.org/post` (and other standard HTTP endpoints) ### Parameters #### Path Parameters None #### Query Parameters - **param** (string) - Optional - Description for query parameters #### Request Body - **body** (bytes, string, file, etc.) - Optional - The request body content ### Request Example ```rust use ureq::Agent; use std::time::Duration; // Build agent with custom config let agent: Agent = Agent::config_builder() .timeout_global(Some(Duration::from_secs(10))) .timeout_connect(Some(Duration::from_secs(3))) .max_redirects(5) .user_agent("my-app/1.0") .build() .into(); // Connection is reused across requests to the same host let page1 = agent.get("https://httpbin.org/get") .call()? .body_mut() .read_to_string()?; let page2 = agent.post("https://httpbin.org/post") .send("some data")? .body_mut() .read_to_string()?; // Clone shares the connection pool — useful for multi-threaded programs let agent2 = agent.clone(); std::thread::spawn(move || { agent2.get("https://httpbin.org/get").call().ok(); }); # Ok::<_, ureq::Error>(()) ``` ### Response #### Success Response (200) - **body** (string, bytes, etc.) - The response body content #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Build multipart/form-data requests with ureq::unversioned::multipart::Form Source: https://context7.com/algesten/ureq/llms.txt Use the `Form` struct to construct `multipart/form-data` requests for file uploads and mixed-content forms. The `Content-Type` header, including the boundary, is set automatically. This API is unversioned and does not follow semver. ```rust use ureq::unversioned::multipart::{Form, Part}; // Simple text fields let resp = ureq::post("https://httpbin.org/post") .send( Form::new() .text("username", "alice") .text("description", "profile update") )?; ``` ```rust // File upload with auto-detected MIME type and filename let resp = ureq::post("https://httpbin.org/post") .send( Form::new() .text("description", "my avatar") .file("avatar", "photo.jpg")? )?; ``` ```rust // Full control with Part builder let resp = ureq::post("https://httpbin.org/post") .send( Form::new() .part( "document", Part::file("report.pdf")? .file_name("Q4-2024-report.pdf") .mime_str("application/pdf")?, ) .part( "thumbnail", Part::bytes(b"\x89PNG\r\n") .file_name("thumb.png") .mime_str("image/png")?, ) )?; ``` -------------------------------- ### Custom Request Body Sources with SendBody Source: https://context7.com/algesten/ureq/llms.txt Illustrates using `SendBody` to wrap `Read` implementations for request bodies. Use `from_reader` for borrowed readers (chunked transfer) and `from_owned_reader` for owned readers. Response bodies can also be proxied directly. ```rust use ureq::SendBody; use std::io::Cursor; // From a shared &mut dyn Read — uses Transfer-Encoding: chunked let mut data = Cursor::new(vec![42u8; 153_600]); ureq::post("https://httpbin.org/post") .content_type("application/octet-stream") .send(SendBody::from_reader(&mut data)?); // From an owned reader — static lifetime, sendable to threads let owned = Cursor::new(b"owned data".to_vec()); let body = SendBody::from_owned_reader(owned); ureq::post("https://httpbin.org/post") .send(body)?; // Proxy a response body directly to another request let mut source_resp = ureq::get("https://httpbin.org/bytes/512").call()?; // Response implements AsSendBody — body is streamed through ureq::put("https://httpbin.org/put") .send(source_resp)?; # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Enable ureq Features Source: https://github.com/algesten/ureq/blob/main/README.md Specify features for ureq in Cargo.toml to customize its functionality and dependency tree. Features like 'socks-proxy' and 'charset' can be enabled. ```toml ureq = { version = "3", features = ["socks-proxy", "charset"] } ``` -------------------------------- ### Send URL-encoded Form Data with ureq Source: https://context7.com/algesten/ureq/llms.txt Submit data as `application/x-www-form-urlencoded` using `.send_form()`. This method accepts slices of key-value pairs or iterators of owned strings, automatically URL-encoding both keys and values. ```rust // Slice of key-value pairs let form_data = [ ("username", "alice"), ("password", "s3cr3t!"), ("remember_me", "true"), ]; let resp = ureq::post("https://httpbin.org/post") .send_form(form_data)?; assert_eq!(resp.status(), 200); // Also accepts iterators of owned strings let fields: Vec<(String, String)> = vec![ ("name".to_string(), "Martin Björn".to_string()), ("city".to_string(), "Göteborg".to_string()), ]; ureq::post("https://httpbin.org/post") .send_form(fields)?; # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Manage cookies with ureq's persistent cookie jar Source: https://context7.com/algesten/ureq/llms.txt When the `cookies` feature is enabled, each `Agent` maintains a persistent cookie jar. This jar is automatically sent with matching requests and updated from `Set-Cookie` response headers. The cookie jar can be inspected, persisted to disk, and loaded from disk. ```rust use ureq::Agent; let agent = Agent::new_with_defaults(); // Cookies returned by this request are stored agent.get("https://www.google.com/").call()?; ``` ```rust // Inspect and persist the cookie jar { let jar = agent.cookie_jar_lock(); for cookie in jar.iter() { println!(" {} = {}", cookie.name(), cookie.value()); } // Persist to disk let mut file = std::fs::File::create("cookies.json")?; jar.save_json(&mut file)?; // jar.release() is called on drop, releasing the lock } // Subsequent requests to the same domain automatically send stored cookies let resp = agent.get("https://www.google.com/").call()?; ``` -------------------------------- ### ureq::get / ureq::post / ureq::put / ureq::delete / ureq::patch Source: https://context7.com/algesten/ureq/llms.txt These are top-level convenience functions for making one-off HTTP requests. They are the simplest way to make requests when session state like cookies or connection pooling is not needed. ```APIDOC ## ureq::get / ureq::post / ureq::put / ureq::delete / ureq::patch ### Description One-shot HTTP methods that create a use-once internal `Agent`. These are the simplest entry point for making requests when no session state (cookies, connection pool) needs to be reused. ### Method GET, POST, PUT, DELETE, PATCH ### Endpoint `https://httpbin.org/get` `https://httpbin.org/post` `https://httpbin.org/put` `https://httpbin.org/delete` `https://httpbin.org/patch` ### Parameters #### Path Parameters None #### Query Parameters - **param** (string) - Optional - Description for query parameters #### Request Body - **body** (bytes, string, file, etc.) - Optional - The request body content ### Request Example ```rust use ureq::Error; // Simple GET — read response as string let body: String = ureq::get("https://httpbin.org/get") .header("Accept", "application/json") .call()? .body_mut() .read_to_string()?; // POST with raw bytes body let resp = ureq::post("https://httpbin.org/post") .header("Content-Type", "application/octet-stream") .send(&[0u8; 64])?; assert_eq!(resp.status(), 200); // DELETE with query parameters ureq::delete("https://httpbin.org/delete") .query("id", "42") .query("confirm", "true") .call()?; // PATCH with string body ureq::patch("https://httpbin.org/patch") .content_type("text/plain") .send("hello world")?; // PUT with a File (sends Content-Length automatically) let file = std::fs::File::open("data.bin")?; ureq::put("https://httpbin.org/put") .send(file)?; // Error handling — status codes 4xx/5xx are Err by default match ureq::get("https://httpbin.org/status/404").call() { Ok(_) => println!("ok"), Err(Error::StatusCode(code)) => println!("server returned {}", code), Err(e) => println!("transport/io error: {}", e), } # Ok::<_, ureq::Error>(()) ``` ### Response #### Success Response (200) - **body** (string, bytes, etc.) - The response body content #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Add Headers to ureq Request Source: https://context7.com/algesten/ureq/llms.txt Set custom headers for a request using the `.header()` method on a RequestBuilder. Multiple headers can be added. ```rust use ureq::Agent; let agent = ureq::agent(); // --- Headers --- let resp = agent.get("https://httpbin.org/headers") .header("X-Custom", "value") .header("Authorization", "Bearer token123") .call()?; ``` -------------------------------- ### Add Query Parameters to ureq Request Source: https://context7.com/algesten/ureq/llms.txt Append URL-encoded query parameters to a request using `.query()` for single pairs or `.query_pairs()` for multiple pairs. Parameters are automatically percent-encoded. ```rust use ureq::Agent; let agent = ureq::agent(); // --- Query parameters (auto percent-encoded) --- let resp = agent.get("https://httpbin.org/get") .query("search", "hello world") // encodes to search=hello%20world .query("page", "1") .call()?; // --- Multiple query pairs at once --- let params = [("format", "json"), ("limit", "100")]; let resp = agent.get("https://httpbin.org/get") .query_pairs(params) .call()?; ``` -------------------------------- ### Send JSON Request Body and Read JSON Response with ureq Source: https://context7.com/algesten/ureq/llms.txt When the `json` feature is enabled, use `.send_json()` to serialize a struct or serde_json::Value as the request body, automatically setting `Content-Type: application/json`. Use `.read_json()` to deserialize the response body. ```rust use serde::{Deserialize, Serialize}; #[derive(Serialize)] struct CreateUser { name: String, email: String, } #[derive(Deserialize, Debug)] struct UserResponse { id: u64, name: String, } // Send JSON and read JSON response let new_user = CreateUser { name: "Alice".to_string(), email: "alice@example.com".to_string(), }; let user: UserResponse = ureq::post("https://httpbin.org/post") .send_json(&new_user)? .body_mut() .read_json::()?; // Using serde_json::Value for dynamic JSON use serde_json::{json, Value}; let payload = json!({ "query": "select * from users", "limit": 10 }); let result: Value = ureq::post("https://httpbin.org/post") .send_json(&payload)? .body_mut() .read_json()?; println!("json field: {}", result["json"]); # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Read Response Body to String Source: https://context7.com/algesten/ureq/llms.txt Reads the response body into a String. Invalid UTF-8 characters are replaced with '?'. A default 10 MB limit is applied. ```rust use std::io::Read; // Read to String (limit 10 MB, invalid UTF-8 replaced with '?') let mut resp = ureq::get("https://httpbin.org/robots.txt").call()?; let text: String = resp.body_mut().read_to_string()?; ``` -------------------------------- ### Streaming Response Body as Read Handle Source: https://context7.com/algesten/ureq/llms.txt Consumes the response body as a streaming `Read` handle. This method does not impose a size limit, so caution is advised with untrusted servers. ```rust // As a streaming Read (no limit — beware malicious servers) let mut resp = ureq::get("https://httpbin.org/bytes/100").call()?; let mut buf = Vec::new(); resp.body_mut().as_reader().read_to_end(&mut buf)?; ``` -------------------------------- ### Accessing Response Body Metadata Source: https://context7.com/algesten/ureq/llms.txt Retrieves metadata about the response body, such as its MIME type and content length. ```rust // Body metadata let resp = ureq::get("https://httpbin.org/json").call()?; println!("mime: {:?}", resp.body().mime_type()); // Some("application/json") println!("len: {:?}", resp.body().content_length()); // Some(429) # Ok::<_, ureq::Error>(()) ``` -------------------------------- ### Custom Fetch Function with Error Handling Source: https://context7.com/algesten/ureq/llms.txt A function that fetches data and handles various `ureq::Error` types, including status codes, host resolution failures, timeouts, and I/O errors. ```rust use ureq::Error; fn fetch(url: &str) -> Result { match ureq::get(url).call() { Ok(mut resp) => Ok(resp.body_mut().read_to_string()?), // Server returned a 4xx or 5xx status Err(Error::StatusCode(code)) => { eprintln!("HTTP error: {}", code); Err(Error::StatusCode(code)) } // DNS lookup failed Err(Error::HostNotFound) => { eprintln!("Could not resolve host"); Err(Error::HostNotFound) } // Timed out (requires timeout to be configured) Err(Error::Timeout(which)) => { eprintln!("Timed out at: {}", which); Err(Error::Timeout(which)) } // TCP / I/O error Err(Error::Io(e)) => { eprintln!("IO error: {}", e); Err(Error::Io(e)) } Err(e) => Err(e), } } ``` -------------------------------- ### Read Response Body to Bytes Source: https://context7.com/algesten/ureq/llms.txt Reads the response body into a Vec. A default 10 MB limit is applied. ```rust // Read to Vec (limit 10 MB) let mut resp = ureq::get("https://httpbin.org/bytes/1024").call()?; let bytes: Vec = resp.body_mut().read_to_vec()?; assert_eq!(bytes.len(), 1024); ``` -------------------------------- ### Streaming Response Body with Custom Limit Source: https://context7.com/algesten/ureq/llms.txt Reads the response body into a Vec with an explicitly configured size limit, useful for responses larger than the default 10 MB. ```rust // Streaming with explicit limit (for files > 10 MB) let mut resp = ureq::get("https://httpbin.org/bytes/1024").call()?; let data = resp.body_mut() .with_config() .limit(50 * 1024 * 1024) // 50 MB limit .read_to_vec()?; ``` -------------------------------- ### Bump Patch Version with cargo-bump Source: https://github.com/algesten/ureq/blob/main/RELEASE.txt Increment the patch version of the project in Cargo.toml. This command is part of the `cargo-bump` utility. ```bash cargo bump patch ``` -------------------------------- ### URL-encoded Form Submission Source: https://context7.com/algesten/ureq/llms.txt Demonstrates how to send data as `application/x-www-form-urlencoded` using `RequestBuilder::send_form`, with automatic URL encoding for keys and values. ```APIDOC ## `RequestBuilder::send_form` — URL-encoded form submission Sends data as `application/x-www-form-urlencoded`. Keys and values are automatically URL-encoded. ```rust // Slice of key-value pairs let form_data = [ ("username", "alice"), ("password", "s3cr3t!"), ("remember_me", "true"), ]; let resp = ureq::post("https://httpbin.org/post") .send_form(form_data)?; assert_eq!(resp.status(), 200); // Also accepts iterators of owned strings let fields: Vec<(String, String)> = vec![ ("name".to_string(), "Martin Björn".to_string()), ("city".to_string(), "Göteborg".to_string()), ]; ureq::post("https://httpbin.org/post") .send_form(fields)?; # Ok::<_, ureq::Error>(()) ``` ``` -------------------------------- ### Reading Response Bodies Source: https://context7.com/algesten/ureq/llms.txt The `Body` struct allows consuming response content in various formats like String, raw bytes, or as a streaming reader. It includes a default 10 MB size limit to prevent memory exhaustion, which can be overridden. ```APIDOC ## Reading Response Bodies The `Body` struct returned in `Response` provides multiple ways to consume the response: as a string, raw bytes, JSON, or a streaming `Read` handle. A default 10 MB size limit protects against memory exhaustion. ```rust use std::io::Read; // Read to String (limit 10 MB, invalid UTF-8 replaced with '?') let mut resp = ureq::get("https://httpbin.org/robots.txt").call()?; let text: String = resp.body_mut().read_to_string()?; // Read to Vec (limit 10 MB) let mut resp = ureq::get("https://httpbin.org/bytes/1024").call()?; let bytes: Vec = resp.body_mut().read_to_vec()?; assert_eq!(bytes.len(), 1024); // Streaming with explicit limit (for files > 10 MB) let mut resp = ureq::get("https://httpbin.org/bytes/1024").call()?; let data = resp.body_mut() .with_config() .limit(50 * 1024 * 1024) // 50 MB limit .read_to_vec()?; // As a streaming Read (no limit — beware malicious servers) let mut resp = ureq::get("https://httpbin.org/bytes/100").call()?; let mut buf = Vec::new(); resp.body_mut().as_reader().read_to_end(&mut buf)?; // Owned reader — can be sent to another thread let resp = ureq::get("https://httpbin.org/bytes/100").call()?; let (_, body) = resp.into_parts(); let reader = body.into_reader(); std::thread::spawn(move || { let mut buf = Vec::new(); reader.take(1024).read_to_end(&mut buf).ok(); }); // Body metadata let resp = ureq::get("https://httpbin.org/json").call()?; println!("mime: {:?}", resp.body().mime_type()); // Some("application/json") println!("len: {:?}", resp.body().content_length()); // Some(429) # Ok::<_, ureq::Error>(()) ``` ```