rust_webx_host/
problem_response.rs1use rust_webx_core::http::IHttpContext;
4use rust_webx_core::problem::ProblemDetails;
5use std::collections::HashMap;
6
7pub fn problem_status_title(status: u16) -> &'static str {
9 match status {
10 400 => "Bad Request",
11 401 => "Unauthorized",
12 403 => "Forbidden",
13 404 => "Not Found",
14 405 => "Method Not Allowed",
15 409 => "Conflict",
16 413 => "Payload Too Large",
17 415 => "Unsupported Media Type",
18 422 => "Unprocessable Entity",
19 429 => "Too Many Requests",
20 500 => "Internal Server Error",
21 502 => "Bad Gateway",
22 503 => "Service Unavailable",
23 504 => "Gateway Timeout",
24 _ => "Error",
25 }
26}
27
28pub fn build_problem(status: u16, detail: impl Into<String>) -> ProblemDetails {
30 ProblemDetails {
31 typ: Some(format!("https://httpstatuses.com/{}", status)),
32 title: problem_status_title(status).into(),
33 status,
34 detail: Some(detail.into()),
35 instance: None,
36 extensions: None,
37 }
38}
39
40pub fn problem_to_bytes(problem: &ProblemDetails) -> Vec<u8> {
42 serde_json::to_vec(problem).unwrap_or_default()
43}
44
45pub async fn write_problem_response(ctx: &mut dyn IHttpContext, problem: ProblemDetails) {
47 let status = problem.status;
48 ctx.response_mut().set_status(status);
49 ctx.response_mut()
50 .set_header("content-type", "application/problem+json");
51 let _ = ctx
52 .response_mut()
53 .write_bytes(problem_to_bytes(&problem))
54 .await;
55}
56
57pub async fn write_problem(ctx: &mut dyn IHttpContext, status: u16, detail: impl Into<String>) {
59 write_problem_response(ctx, build_problem(status, detail)).await;
60}
61
62pub async fn write_forbidden(
64 ctx: &mut dyn IHttpContext,
65 detail: impl Into<String>,
66 extensions: HashMap<String, serde_json::Value>,
67) {
68 let mut problem = build_problem(403, detail);
69 if !extensions.is_empty() {
70 problem.extensions = Some(extensions);
71 }
72 write_problem_response(ctx, problem).await;
73}