### Create Problem Details Object with Extensions Source: https://github.com/frenetisch-applaudierend/problem-details-rs/blob/main/README.md Demonstrates creating a ProblemDetails object with custom extensions, including balance and accounts, and serializing it to JSON. This is useful for generating RFC-compliant error responses. ```rust use http::Uri; use problem_details::ProblemDetails; #[derive(serde::Serialize)] struct OutOfCreditExt { balance: u32, accounts: Vec, } let details = ProblemDetails::new() .with_type(Uri::from_static("https://example.com/probs/out-of-credit")) .with_title("You do not have enough credit.") .with_detail("Your current balance is 30, but that costs 50.") .with_instance(Uri::from_static("/account/12345/msgs/abc")) .with_extensions(OutOfCreditExt { balance: 30, accounts: vec![ "/account/12345".to_string(), "/account/67890".to_string(), ], }); let json = serde_json::to_value(&details).unwrap(); assert_eq!(json, serde_json::json!({ "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": [ "/account/12345", "/account/67890" ] })); ``` -------------------------------- ### Build Problem Details with Builder Pattern Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Constructs fully-configured problem details objects using a fluent builder pattern. Allows setting type URI, status, title, detail, and instance fields. ```rust use http::{StatusCode, Uri}; use problem_details::ProblemDetails; let details = ProblemDetails::new() .with_type(Uri::from_static("https://example.com/probs/out-of-credit")) .with_status(StatusCode::FORBIDDEN) .with_title("You do not have enough credit.") .with_detail("Your current balance is 30, but that costs 50.") .with_instance(Uri::from_static("/account/12345/msgs/abc")); let json = serde_json::to_value(&details).unwrap(); assert_eq!(json, serde_json::json!({ "type": "https://example.com/probs/out-of-credit", "status": 403, "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc" })); ``` -------------------------------- ### Add Custom Extensions to Problem Details Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Integrates application-specific fields into problem details by defining an extension struct that derives `serde::Serialize` and `serde::Deserialize`. These fields are flattened into the serialized output. ```rust use http::{StatusCode, Uri}; use problem_details::ProblemDetails; #[derive(serde::Serialize, serde::Deserialize)] struct OutOfCreditExt { balance: u32, accounts: Vec, } let details = ProblemDetails::new() .with_type(Uri::from_static("https://example.com/probs/out-of-credit")) .with_title("You do not have enough credit.") .with_detail("Your current balance is 30, but that costs 50.") .with_instance(Uri::from_static("/account/12345/msgs/abc")) .with_extensions(OutOfCreditExt { balance: 30, accounts: vec![ "/account/12345".to_string(), "/account/67890".to_string(), ], }); let json = serde_json::to_value(&details).unwrap(); assert_eq!(json, serde_json::json!({ "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] })); ``` -------------------------------- ### Create Problem Details from Status Code Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Automatically sets status and title fields based on the canonical reason phrase of an HTTP status code. Useful for standard error responses. ```rust use http::StatusCode; use problem_details::ProblemDetails; // Create from status code - title is automatically set to canonical reason let details = ProblemDetails::from_status_code(StatusCode::NOT_FOUND); assert_eq!(details.status, Some(StatusCode::NOT_FOUND)); assert_eq!(details.title, Some("Not Found".to_string())); // Serialize to JSON let json = serde_json::to_value(&details).unwrap(); // Output: {"status": 404, "title": "Not Found"} ``` -------------------------------- ### Utoipa OpenAPI Integration with ProblemDetails Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Use ProblemDetails with utoipa for automatic OpenAPI schema generation. Define responses for different ProblemDetails types to ensure accurate documentation. ```rust use axum::routing::get; use http::StatusCode; use problem_details::{ProblemDetails, JsonProblemDetails, XmlProblemDetails}; use utoipa_axum::{router::OpenApiRouter, routes}; #[utoipa::path( get, path = "/", responses( (status = OK, body = String, description = "Success"), (status = IM_A_TEAPOT, body = ProblemDetails, description = "I'm a teapot!"), ), )] async fn default_handler() -> Result<&'static str, ProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::IM_A_TEAPOT) .with_detail("short and stout")) } #[utoipa::path( get, path = "/json", responses( (status = OK, body = String, description = "Success"), ( status = BAD_REQUEST, body = ProblemDetails, description = "Bad request", content_type = JsonProblemDetails::<()>::CONTENT_TYPE, ), ), )] async fn json_handler() -> Result<&'static str, JsonProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::BAD_REQUEST) .with_detail("Invalid input") .into()) } let (app, api) = OpenApiRouter::new() .routes(routes!(default_handler)) .routes(routes!(json_handler)) .split_for_parts(); ``` -------------------------------- ### Serialize Problem Details with Custom Extensions Source: https://github.com/frenetisch-applaudierend/problem-details-rs/blob/main/README.md Shows how to add custom extension fields to a ProblemDetails object using a struct and serialize it to JSON. The extension fields are flattened into the main object during serialization. ```rust use problem_details::ProblemDetails; #[derive(serde::Serialize, serde::Deserialize)] struct MyExt { foo: String, bar: u32, } let details = ProblemDetails::new() .with_title("Extensions test") .with_extensions(MyExt { foo: "Hello".to_string(), bar: 42, }); let json = serde_json::to_value(&details).unwrap(); assert_eq!(json, serde_json::json!({ "title": "Extensions test", "foo": "Hello", "bar": 42 })); ``` -------------------------------- ### Axum Integration for ProblemDetails Error Responses Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Return `ProblemDetails` or its variants directly from Axum handlers. They implement `IntoResponse`, defaulting to JSON. Explicitly return `JsonProblemDetails` or `XmlProblemDetails` for specific content types. ```rust use axum::{Router, routing::get}; use http::StatusCode; use problem_details::{ProblemDetails, JsonProblemDetails, XmlProblemDetails}; // ProblemDetails implements IntoResponse - defaults to JSON async fn default_handler() -> Result<&'static str, ProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::IM_A_TEAPOT) .with_detail("short and stout")) } // Explicit JSON format async fn json_handler() -> Result<&'static str, JsonProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::BAD_REQUEST) .with_detail("Invalid request") .into()) } // Explicit XML format async fn xml_handler() -> Result<&'static str, XmlProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::INTERNAL_SERVER_ERROR) .with_detail("Server error") .into()) } let app = Router::new() .route("/", get(default_handler)) .route("/json", get(json_handler)) .route("/xml", get(xml_handler)); ``` -------------------------------- ### Deserialize Problem Details with Extensions Source: https://github.com/frenetisch-applaudierend/problem-details-rs/blob/main/README.md Illustrates how to deserialize a JSON string into a ProblemDetails object that includes custom extensions. The extension type must be specified as a generic parameter. ```rust let details: ProblemDetails = serde_json::from_str(json).unwrap(); ``` -------------------------------- ### Deserialize Problem Details with Typed Extensions Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Deserialize problem details from JSON, including custom typed extensions. Ensure the extension struct derives `serde::Serialize` and `serde::Deserialize`. ```rust use http::StatusCode; use problem_details::ProblemDetails; #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)] struct MyExtensions { foo: String, bar: u32, } let json = r#"{ "type": "test:type", "status": 500, "title": "Test Title", "detail": "Test Detail", "instance": "test:instance", "foo": "Foo", "bar": 42 }"#; // Deserialize with typed extensions let details: ProblemDetails = serde_json::from_str(json).unwrap(); assert_eq!(details.status, Some(StatusCode::INTERNAL_SERVER_ERROR)); assert_eq!(details.title, Some("Test Title".to_string())); assert_eq!(details.extensions.foo, "Foo"); assert_eq!(details.extensions.bar, 42); ``` -------------------------------- ### Poem Integration for ProblemDetails Error Responses Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Return `ProblemDetails` or its variants from Poem handlers. They are automatically handled as error responses. Use `JsonProblemDetails` or `XmlProblemDetails` for specific content types. ```rust use poem::{Route, get, handler}; use http::StatusCode; use problem_details::{ProblemDetails, JsonProblemDetails, XmlProblemDetails}; #[handler] async fn default_handler() -> Result<&'static str, ProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::IM_A_TEAPOT) .with_detail("short and stout")) } #[handler] async fn json_handler() -> Result<&'static str, JsonProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::BAD_REQUEST) .with_detail("Invalid request") .into()) } #[handler] async fn xml_handler() -> Result<&'static str, XmlProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::INTERNAL_SERVER_ERROR) .with_detail("Server error") .into()) } let app = Route::new() .at("/", get(default_handler)) .at("/json", get(json_handler)) .at("/xml", get(xml_handler)); ``` -------------------------------- ### Actix-Web Integration for ProblemDetails Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Return ProblemDetails from Actix-Web handlers as error responses. Ensure the appropriate ProblemDetails type (e.g., JsonProblemDetails, XmlProblemDetails) is returned to match the desired content type. ```rust use actix_web::{App, HttpServer, web}; use http::StatusCode; use problem_details::{ProblemDetails, JsonProblemDetails, XmlProblemDetails}; async fn default_handler() -> Result<&'static str, ProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::IM_A_TEAPOT) .with_detail("short and stout")) } async fn json_handler() -> Result<&'static str, JsonProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::BAD_REQUEST) .with_detail("Invalid request") .into()) } async fn xml_handler() -> Result<&'static str, XmlProblemDetails> { Err(ProblemDetails::from_status_code(StatusCode::INTERNAL_SERVER_ERROR) .with_detail("Server error") .into()) } let app = App::new() .route("/", web::get().to(default_handler)) .route("/json", web::get().to(json_handler)) .route("/xml", web::get().to(xml_handler)); ``` -------------------------------- ### XmlProblemDetails for XML Responses Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Use the `XmlProblemDetails` wrapper for XML serialization, ensuring the `application/problem+xml` content type. This wrapper handles XML formatting and content type. ```rust use http::StatusCode; use problem_details::{XmlProblemDetails, ProblemDetails}; // XmlProblemDetails sets content-type to "application/problem+xml" let xml_details: XmlProblemDetails = ProblemDetails::from_status_code(StatusCode::NOT_FOUND) .with_detail("Resource not found") .into(); assert_eq!(XmlProblemDetails::<()>::CONTENT_TYPE, "application/problem+xml"); // Serialize to XML body string let body = xml_details.to_body_string().unwrap(); // Output: 404Not FoundResource not found ``` -------------------------------- ### Add Dynamic Extensions with HashMap Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Utilizes a `HashMap` to incorporate dynamic extension fields when the structure is not known at compile time. This allows for flexible addition of arbitrary key-value pairs. ```rust use std::collections::HashMap; use problem_details::ProblemDetails; let mut extensions = HashMap::::new(); extensions.insert("foo".to_string(), serde_json::json!("Hello")); extensions.insert("bar".to_string(), serde_json::json!(42)); let details = ProblemDetails::new() .with_title("Dynamic extensions example") .with_extensions(extensions); let json = serde_json::to_value(&details).unwrap(); assert_eq!(json, serde_json::json!({ "title": "Dynamic extensions example", "foo": "Hello", "bar": 42 })); ``` -------------------------------- ### JsonProblemDetails for Explicit JSON Responses Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Use the `JsonProblemDetails` wrapper to ensure responses have the `application/problem+json` content type. This wrapper automatically sets the content type during serialization. ```rust use http::StatusCode; use problem_details::{JsonProblemDetails, ProblemDetails}; // JsonProblemDetails sets content-type to "application/problem+json" let json_details: JsonProblemDetails = ProblemDetails::from_status_code(StatusCode::BAD_REQUEST) .with_detail("Invalid input provided") .into(); // Get the content type constant assert_eq!(JsonProblemDetails::<()>::CONTENT_TYPE, "application/problem+json"); // Serialize to body string let body = json_details.to_body_string().unwrap(); // Output: {"status":400,"title":"Bad Request","detail":"Invalid input provided"} ``` -------------------------------- ### Display Format for Logging ProblemDetails Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt ProblemDetails implements the Display trait for human-readable logging output. The format is "[type status] title: detail". ```rust use http::{StatusCode, Uri}; use problem_details::ProblemDetails; let details = ProblemDetails::new() .with_type(Uri::from_static("test:type")) .with_status(StatusCode::NOT_FOUND) .with_title("Test Title") .with_detail("Test Detail"); // Format: [type status] title: detail assert_eq!(details.to_string(), "[test:type 404] Test Title: Test Detail"); // Empty details let empty = ProblemDetails::new(); assert_eq!(empty.to_string(), "[about:blank]"); // Status only let status_only = ProblemDetails::from_status_code(StatusCode::NOT_FOUND); assert_eq!(status_only.to_string(), "[about:blank 404] Not Found"); ``` -------------------------------- ### ProblemType for Custom Problem URIs Source: https://context7.com/frenetisch-applaudierend/problem-details-rs/llms.txt Use ProblemType to work with problem type URIs, which defaults to "about:blank" per RFC specification. ProblemType dereferences to a Uri, allowing access to its components. ```rust use http::Uri; use problem_details::ProblemType; // Create from URI let uri = Uri::from_static("https://example.com/problem"); let problem_type = ProblemType::from(uri); assert_eq!(problem_type.to_string(), "https://example.com/problem"); // Default is "about:blank" let default_type = ProblemType::default(); assert_eq!(default_type.to_string(), "about:blank"); // ProblemType derefs to Uri let problem_type = ProblemType::from(Uri::from_static("https://example.com/error")); let uri_ref: &Uri = &problem_type; assert_eq!(uri_ref.host(), Some("example.com")); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.