servers/http/result/
error_result.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use axum::response::{IntoResponse, Response};
use axum::Json;
use common_error::ext::ErrorExt;
use common_error::from_err_code_msg_to_header;
use common_error::status_code::StatusCode;
use common_telemetry::{debug, error};
use serde::{Deserialize, Serialize};

use crate::error::status_code_to_http_status;

#[derive(Serialize, Deserialize, Debug)]
pub struct ErrorResponse {
    code: u32,
    error: String,
    execution_time_ms: u64,
}

impl ErrorResponse {
    pub fn from_error(error: impl ErrorExt) -> Self {
        let code = error.status_code();

        if code.should_log_error() {
            error!(error; "Failed to handle HTTP request");
        } else {
            debug!("Failed to handle HTTP request, err: {:?}", error);
        }

        Self::from_error_message(code, error.output_msg())
    }

    pub fn from_error_message(code: StatusCode, msg: String) -> Self {
        ErrorResponse {
            code: code as u32,
            error: msg,
            execution_time_ms: 0,
        }
    }

    pub fn with_execution_time(mut self, execution_time: u64) -> Self {
        self.execution_time_ms = execution_time;
        self
    }

    pub fn execution_time_ms(&self) -> u64 {
        self.execution_time_ms
    }

    pub fn code(&self) -> u32 {
        self.code
    }

    pub fn error(&self) -> &str {
        &self.error
    }
}

impl IntoResponse for ErrorResponse {
    fn into_response(self) -> Response {
        let code = self.code;
        let execution_time = self.execution_time_ms;
        let new_header = from_err_code_msg_to_header(
            code,
            &format!(
                "error: {}, execution_time_ms: {}",
                self.error, execution_time
            ),
        );
        let mut resp = Json(self).into_response();
        resp.headers_mut().extend(new_header);

        let status = StatusCode::from_u32(code).unwrap_or(StatusCode::Unknown);
        let status_code = status_code_to_http_status(&status);

        (status_code, resp).into_response()
    }
}