1use crate::request_id::current_request_id;
4use crate::response::Response;
5use serde::Serialize;
6use serde_json::{json, Map, Value};
7
8pub fn problem_response(
12 status: u16,
13 title: impl Into<String>,
14 detail: impl Into<String>,
15 extensions: impl IntoIterator<Item = (String, Value)>,
16) -> Response {
17 let title = title.into();
18 let detail = detail.into();
19 let mut body = Map::new();
20 body.insert("type".into(), json!("about:blank"));
21 body.insert("title".into(), json!(title));
22 body.insert("status".into(), json!(status));
23 body.insert("detail".into(), json!(detail));
24 if let Some(rid) = current_request_id() {
25 body.insert("request_id".into(), json!(rid));
26 }
27 for (k, v) in extensions {
28 body.insert(k, v);
29 }
30 Response::json(&Value::Object(body))
31 .status(status)
32 .header("content-type", "application/problem+json")
33}
34
35pub fn error_to_problem(err: crate::Error) -> Response {
37 use crate::Error;
38 match err {
39 Error::Response(res) => *res,
40 Error::NotFound => problem_response(404, "Not Found", "Not Found", []),
41 Error::Unauthorized => problem_response(401, "Unauthorized", "Unauthorized", []),
42 Error::Forbidden => problem_response(403, "Forbidden", "Forbidden", []),
43 Error::BadRequest(msg) => problem_response(400, "Bad Request", msg, []),
44 Error::PayloadTooLarge => {
45 problem_response(413, "Payload Too Large", "Payload Too Large", [])
46 }
47 Error::MethodNotAllowed => {
48 problem_response(405, "Method Not Allowed", "Method Not Allowed", [])
49 }
50 Error::Internal(msg) => problem_response(500, "Internal Server Error", msg, []),
51 Error::Json(e) => problem_response(400, "Bad Request", format!("JSON error: {e}"), []),
52 Error::Io(e) => {
53 problem_response(500, "Internal Server Error", format!("IO error: {e}"), [])
54 }
55 }
56}
57
58pub fn problem_with_errors<E: Serialize>(
60 status: u16,
61 title: impl Into<String>,
62 detail: impl Into<String>,
63 errors: &[E],
64) -> Response {
65 let errors = serde_json::to_value(errors).unwrap_or(json!([]));
66 problem_response(status, title, detail, [("errors".into(), errors)])
67}