humblegen_rt/
service_protocol.rs1use hyper::Body;
6use hyper::Response;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Serialize, Deserialize)]
12pub struct ErrorResponse {
13 pub code: u16,
14 pub kind: ErrorResponseKind,
15}
16
17pub trait ToErrorResponse {
18 fn to_error_response(self) -> ErrorResponse;
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22pub enum ErrorResponseKind {
23 Service(ServiceError),
24 Runtime(RuntimeError),
25}
26
27#[derive(Debug, Serialize, Deserialize)]
32pub enum ServiceError {
33 Authentication,
36 Authorization,
39 Internal(String),
45}
46
47#[derive(Debug, Serialize, Deserialize)]
50pub enum RuntimeError {
51 NoServiceMounted,
52 ServiceMountsAmbiguous,
53 NoRouteMountedInService {
54 service: String,
55 },
56 RouteMountsAmbiguous {
57 service: String,
58 },
59 RouteParamInvalid {
60 param_name: String,
61 parse_error: String,
62 },
63 QueryInvalid(String),
64 PostBodyReadError(String),
65 PostBodyInvalid(String),
66 SerializeHandlerResponse(String),
67 SerializeErrorResponse(String),
68}
69
70impl ErrorResponse {
71 pub fn to_hyper_response(&self) -> Response<Body> {
72 hyper::Response::builder()
73 .status(self.code)
74 .body(
75 serde_json::to_string_pretty(self)
76 .expect("runtime responses must be JSON-serializable")
77 .into(),
78 )
79 .expect("runtime responses must always be buildable")
80 }
81}
82
83impl ToErrorResponse for ServiceError {
84 fn to_error_response(self) -> ErrorResponse {
85 ErrorResponse {
86 code: self.status_code(),
87 kind: ErrorResponseKind::Service(self),
88 }
89 }
90}
91
92impl ToErrorResponse for RuntimeError {
93 fn to_error_response(self) -> ErrorResponse {
94 ErrorResponse {
95 code: self.status_code(),
96 kind: ErrorResponseKind::Runtime(self),
97 }
98 }
99}
100
101impl RuntimeError {
102 fn status_code(&self) -> u16 {
103 match self {
104 RuntimeError::NoServiceMounted => 404,
105 RuntimeError::NoRouteMountedInService { .. } => 404,
106 RuntimeError::RouteMountsAmbiguous { .. } => 500,
107 RuntimeError::ServiceMountsAmbiguous => 500,
108 RuntimeError::RouteParamInvalid { .. } => 400,
109 RuntimeError::QueryInvalid(_) => 400,
110 RuntimeError::PostBodyReadError(_) => 400,
111 RuntimeError::PostBodyInvalid(_) => 400,
112 RuntimeError::SerializeHandlerResponse(_) => 500,
113 RuntimeError::SerializeErrorResponse(_) => 500,
114 }
115 }
116}
117
118impl ServiceError {
119 pub fn status_code(&self) -> u16 {
120 match self {
121 ServiceError::Authentication => 401,
122 ServiceError::Authorization => 403,
123 ServiceError::Internal(_) => 500,
124 }
125 }
126}
127
128impl From<super::handler::ServiceError> for ServiceError {
129 fn from(e: super::handler::ServiceError) -> Self {
130 match e {
131 super::handler::ServiceError::Authentication => ServiceError::Authentication,
132 super::handler::ServiceError::Authorization => ServiceError::Authorization,
133 super::handler::ServiceError::Internal(e) => ServiceError::Internal(format!("{}", e)),
134 }
135 }
136}