Line data Source code
1 : //! Things stolen from `libs/utils/src/http` to add hyper 1.0 compatibility
2 : //! Will merge back in at some point in the future.
3 :
4 : use bytes::Bytes;
5 :
6 : use anyhow::Context;
7 : use http::{Response, StatusCode};
8 : use http_body_util::Full;
9 :
10 : use serde::Serialize;
11 : use utils::http::error::ApiError;
12 :
13 : /// Like [`ApiError::into_response`]
14 0 : pub fn api_error_into_response(this: ApiError) -> Response<Full<Bytes>> {
15 0 : match this {
16 0 : ApiError::BadRequest(err) => HttpErrorBody::response_from_msg_and_status(
17 0 : format!("{err:#?}"), // use debug printing so that we give the cause
18 0 : StatusCode::BAD_REQUEST,
19 0 : ),
20 : ApiError::Forbidden(_) => {
21 0 : HttpErrorBody::response_from_msg_and_status(this.to_string(), StatusCode::FORBIDDEN)
22 : }
23 : ApiError::Unauthorized(_) => {
24 0 : HttpErrorBody::response_from_msg_and_status(this.to_string(), StatusCode::UNAUTHORIZED)
25 : }
26 : ApiError::NotFound(_) => {
27 0 : HttpErrorBody::response_from_msg_and_status(this.to_string(), StatusCode::NOT_FOUND)
28 : }
29 : ApiError::Conflict(_) => {
30 0 : HttpErrorBody::response_from_msg_and_status(this.to_string(), StatusCode::CONFLICT)
31 : }
32 0 : ApiError::PreconditionFailed(_) => HttpErrorBody::response_from_msg_and_status(
33 0 : this.to_string(),
34 0 : StatusCode::PRECONDITION_FAILED,
35 0 : ),
36 0 : ApiError::ShuttingDown => HttpErrorBody::response_from_msg_and_status(
37 0 : "Shutting down".to_string(),
38 0 : StatusCode::SERVICE_UNAVAILABLE,
39 0 : ),
40 0 : ApiError::ResourceUnavailable(err) => HttpErrorBody::response_from_msg_and_status(
41 0 : err.to_string(),
42 0 : StatusCode::SERVICE_UNAVAILABLE,
43 0 : ),
44 0 : ApiError::Timeout(err) => HttpErrorBody::response_from_msg_and_status(
45 0 : err.to_string(),
46 0 : StatusCode::REQUEST_TIMEOUT,
47 0 : ),
48 0 : ApiError::InternalServerError(err) => HttpErrorBody::response_from_msg_and_status(
49 0 : err.to_string(),
50 0 : StatusCode::INTERNAL_SERVER_ERROR,
51 0 : ),
52 : }
53 0 : }
54 :
55 : /// Same as [`utils::http::error::HttpErrorBody`]
56 : #[derive(Serialize)]
57 : struct HttpErrorBody {
58 : pub msg: String,
59 : }
60 :
61 : impl HttpErrorBody {
62 : /// Same as [`utils::http::error::HttpErrorBody::response_from_msg_and_status`]
63 0 : fn response_from_msg_and_status(msg: String, status: StatusCode) -> Response<Full<Bytes>> {
64 0 : HttpErrorBody { msg }.to_response(status)
65 0 : }
66 :
67 : /// Same as [`utils::http::error::HttpErrorBody::to_response`]
68 0 : fn to_response(&self, status: StatusCode) -> Response<Full<Bytes>> {
69 0 : Response::builder()
70 0 : .status(status)
71 0 : .header(http::header::CONTENT_TYPE, "application/json")
72 0 : // we do not have nested maps with non string keys so serialization shouldn't fail
73 0 : .body(Full::new(Bytes::from(serde_json::to_string(self).unwrap())))
74 0 : .unwrap()
75 0 : }
76 : }
77 :
78 : /// Same as [`utils::http::json::json_response`]
79 0 : pub fn json_response<T: Serialize>(
80 0 : status: StatusCode,
81 0 : data: T,
82 0 : ) -> Result<Response<Full<Bytes>>, ApiError> {
83 0 : let json = serde_json::to_string(&data)
84 0 : .context("Failed to serialize JSON response")
85 0 : .map_err(ApiError::InternalServerError)?;
86 0 : let response = Response::builder()
87 0 : .status(status)
88 0 : .header(http::header::CONTENT_TYPE, "application/json")
89 0 : .body(Full::new(Bytes::from(json)))
90 0 : .map_err(|e| ApiError::InternalServerError(e.into()))?;
91 0 : Ok(response)
92 0 : }
|