Skip to main content

servers/http/result/
error_result.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use axum::Json;
16use axum::response::{IntoResponse, Response};
17use common_error::ext::ErrorExt;
18use common_error::from_err_code_msg_to_header;
19use common_error::status_code::StatusCode;
20use common_telemetry::{debug, error};
21use serde::{Deserialize, Serialize};
22
23use crate::error::status_code_to_http_status;
24
25#[derive(Serialize, Deserialize, Debug)]
26pub struct ErrorResponse {
27    code: u32,
28    error: String,
29    execution_time_ms: u64,
30}
31
32impl ErrorResponse {
33    pub fn from_error(error: impl ErrorExt) -> Self {
34        let code = error.status_code();
35        if code.should_log_error() {
36            error!(error; "Failed to handle HTTP request");
37        } else {
38            debug!("Failed to handle HTTP request, err: {:?}", error);
39        }
40        ErrorResponse {
41            code: code as u32,
42            error: error.output_msg(),
43            execution_time_ms: 0,
44        }
45    }
46
47    pub fn from_error_message(code: StatusCode, msg: String) -> Self {
48        if code.should_log_error() {
49            error!("Failed to handle HTTP request: {}", msg);
50        } else {
51            debug!("Failed to handle HTTP request: {}", msg);
52        }
53        ErrorResponse {
54            code: code as u32,
55            error: msg,
56            execution_time_ms: 0,
57        }
58    }
59
60    pub fn with_execution_time(mut self, execution_time: u64) -> Self {
61        self.execution_time_ms = execution_time;
62        self
63    }
64
65    pub fn execution_time_ms(&self) -> u64 {
66        self.execution_time_ms
67    }
68
69    pub fn code(&self) -> u32 {
70        self.code
71    }
72
73    pub fn error(&self) -> &str {
74        &self.error
75    }
76}
77
78impl IntoResponse for ErrorResponse {
79    fn into_response(self) -> Response {
80        let code = self.code;
81        let execution_time = self.execution_time_ms;
82        let new_header = from_err_code_msg_to_header(
83            code,
84            &format!(
85                "error: {}, execution_time_ms: {}",
86                self.error, execution_time
87            ),
88        );
89        let mut resp = Json(self).into_response();
90        resp.headers_mut().extend(new_header);
91
92        let status = StatusCode::from_u32(code).unwrap_or(StatusCode::Unknown);
93        let status_code = status_code_to_http_status(&status);
94
95        (status_code, resp).into_response()
96    }
97}