structured_proxy/transcode/
error.rs1use axum::http::StatusCode;
7use axum::response::{IntoResponse, Response};
8use axum::Json;
9
10pub fn grpc_to_http_status(code: tonic::Code) -> StatusCode {
14 match code {
15 tonic::Code::Ok => StatusCode::OK,
16 tonic::Code::Cancelled => StatusCode::from_u16(499).unwrap_or(StatusCode::BAD_REQUEST),
17 tonic::Code::Unknown => StatusCode::INTERNAL_SERVER_ERROR,
18 tonic::Code::InvalidArgument => StatusCode::BAD_REQUEST,
19 tonic::Code::DeadlineExceeded => StatusCode::GATEWAY_TIMEOUT,
20 tonic::Code::NotFound => StatusCode::NOT_FOUND,
21 tonic::Code::AlreadyExists => StatusCode::CONFLICT,
22 tonic::Code::PermissionDenied => StatusCode::FORBIDDEN,
23 tonic::Code::ResourceExhausted => StatusCode::TOO_MANY_REQUESTS,
24 tonic::Code::FailedPrecondition => StatusCode::BAD_REQUEST,
25 tonic::Code::Aborted => StatusCode::CONFLICT,
26 tonic::Code::OutOfRange => StatusCode::BAD_REQUEST,
27 tonic::Code::Unimplemented => StatusCode::NOT_IMPLEMENTED,
28 tonic::Code::Internal => StatusCode::INTERNAL_SERVER_ERROR,
29 tonic::Code::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
30 tonic::Code::DataLoss => StatusCode::INTERNAL_SERVER_ERROR,
31 tonic::Code::Unauthenticated => StatusCode::UNAUTHORIZED,
32 }
33}
34
35pub fn status_to_response(status: tonic::Status) -> Response {
37 let http_status = grpc_to_http_status(status.code());
38 let body = serde_json::json!({
39 "error": grpc_code_name(status.code()),
40 "message": status.message(),
41 "code": status.code() as i32,
42 });
43 (http_status, Json(body)).into_response()
44}
45
46fn grpc_code_name(code: tonic::Code) -> &'static str {
48 match code {
49 tonic::Code::Ok => "OK",
50 tonic::Code::Cancelled => "CANCELLED",
51 tonic::Code::Unknown => "UNKNOWN",
52 tonic::Code::InvalidArgument => "INVALID_ARGUMENT",
53 tonic::Code::DeadlineExceeded => "DEADLINE_EXCEEDED",
54 tonic::Code::NotFound => "NOT_FOUND",
55 tonic::Code::AlreadyExists => "ALREADY_EXISTS",
56 tonic::Code::PermissionDenied => "PERMISSION_DENIED",
57 tonic::Code::ResourceExhausted => "RESOURCE_EXHAUSTED",
58 tonic::Code::FailedPrecondition => "FAILED_PRECONDITION",
59 tonic::Code::Aborted => "ABORTED",
60 tonic::Code::OutOfRange => "OUT_OF_RANGE",
61 tonic::Code::Unimplemented => "UNIMPLEMENTED",
62 tonic::Code::Internal => "INTERNAL",
63 tonic::Code::Unavailable => "UNAVAILABLE",
64 tonic::Code::DataLoss => "DATA_LOSS",
65 tonic::Code::Unauthenticated => "UNAUTHENTICATED",
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_grpc_to_http_mapping() {
75 assert_eq!(grpc_to_http_status(tonic::Code::Ok), StatusCode::OK);
76 assert_eq!(
77 grpc_to_http_status(tonic::Code::InvalidArgument),
78 StatusCode::BAD_REQUEST
79 );
80 assert_eq!(
81 grpc_to_http_status(tonic::Code::NotFound),
82 StatusCode::NOT_FOUND
83 );
84 assert_eq!(
85 grpc_to_http_status(tonic::Code::AlreadyExists),
86 StatusCode::CONFLICT
87 );
88 assert_eq!(
89 grpc_to_http_status(tonic::Code::PermissionDenied),
90 StatusCode::FORBIDDEN
91 );
92 assert_eq!(
93 grpc_to_http_status(tonic::Code::Unauthenticated),
94 StatusCode::UNAUTHORIZED
95 );
96 assert_eq!(
97 grpc_to_http_status(tonic::Code::ResourceExhausted),
98 StatusCode::TOO_MANY_REQUESTS
99 );
100 assert_eq!(
101 grpc_to_http_status(tonic::Code::Unimplemented),
102 StatusCode::NOT_IMPLEMENTED
103 );
104 assert_eq!(
105 grpc_to_http_status(tonic::Code::Internal),
106 StatusCode::INTERNAL_SERVER_ERROR
107 );
108 assert_eq!(
109 grpc_to_http_status(tonic::Code::Unavailable),
110 StatusCode::SERVICE_UNAVAILABLE
111 );
112 assert_eq!(
113 grpc_to_http_status(tonic::Code::DeadlineExceeded),
114 StatusCode::GATEWAY_TIMEOUT
115 );
116 }
117
118 #[test]
119 fn test_grpc_code_name() {
120 assert_eq!(grpc_code_name(tonic::Code::Ok), "OK");
121 assert_eq!(grpc_code_name(tonic::Code::NotFound), "NOT_FOUND");
122 assert_eq!(
123 grpc_code_name(tonic::Code::Unauthenticated),
124 "UNAUTHENTICATED"
125 );
126 }
127
128 #[test]
129 fn test_status_to_response() {
130 let status = tonic::Status::not_found("user not found");
131 let response = status_to_response(status);
132 assert_eq!(response.status(), StatusCode::NOT_FOUND);
133 }
134}