zino_http/response/
response_code.rs

1use serde::Serialize;
2use std::borrow::Cow;
3use zino_core::SharedString;
4
5/// Trait for response code.
6/// See [Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc7807).
7pub trait ResponseCode {
8    /// A type for the error code.
9    type ErrorCode: Serialize;
10
11    /// A type for the business code.
12    type BusinessCode: Serialize;
13
14    /// 200 Ok.
15    const OK: Self;
16    /// 400 Bad Request.
17    const BAD_REQUEST: Self;
18    /// 500 Internal Server Error.
19    const INTERNAL_SERVER_ERROR: Self;
20
21    /// Status code.
22    fn status_code(&self) -> u16;
23
24    /// Returns `true` if the response is successful.
25    fn is_success(&self) -> bool;
26
27    /// Error code.
28    #[inline]
29    fn error_code(&self) -> Option<Self::ErrorCode> {
30        None
31    }
32
33    /// Business code.
34    #[inline]
35    fn business_code(&self) -> Option<Self::BusinessCode> {
36        None
37    }
38
39    /// A URI reference that identifies the problem type.
40    /// For successful response, it should be `None`.
41    fn type_uri(&self) -> Option<SharedString> {
42        None
43    }
44
45    /// A short, human-readable summary of the problem type.
46    /// For successful response, it should be `None`.
47    fn title(&self) -> Option<SharedString> {
48        None
49    }
50
51    /// A context-specific descriptive message. If the response is not successful,
52    /// it should be a human-readable explanation specific to this occurrence of the problem.
53    fn message(&self) -> Option<SharedString> {
54        None
55    }
56}
57
58macro_rules! impl_response_code {
59    ($Ty:ty) => {
60        impl ResponseCode for $Ty {
61            type ErrorCode = SharedString;
62            type BusinessCode = u16;
63
64            const OK: Self = Self::OK;
65            const BAD_REQUEST: Self = Self::BAD_REQUEST;
66            const INTERNAL_SERVER_ERROR: Self = Self::INTERNAL_SERVER_ERROR;
67
68            #[inline]
69            fn status_code(&self) -> u16 {
70                self.as_u16()
71            }
72
73            #[inline]
74            fn is_success(&self) -> bool {
75                self.is_success()
76            }
77
78            #[inline]
79            fn type_uri(&self) -> Option<SharedString> {
80                None
81            }
82
83            #[inline]
84            fn title(&self) -> Option<SharedString> {
85                if self.is_success() {
86                    None
87                } else {
88                    self.canonical_reason().map(Cow::Borrowed)
89                }
90            }
91
92            #[inline]
93            fn message(&self) -> Option<SharedString> {
94                if self.is_success() {
95                    self.canonical_reason().map(Cow::Borrowed)
96                } else {
97                    None
98                }
99            }
100        }
101    };
102}
103
104impl_response_code!(http::StatusCode);
105
106#[cfg(feature = "http02")]
107impl_response_code!(http02::StatusCode);