-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresponses.rs
184 lines (162 loc) · 5.13 KB
/
responses.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
use crate::api::errors::ApiErrorType;
use serde::Serialize;
use warp::hyper::StatusCode;
//====== JSON HANDLING ======//
/// A JSON formatted reply.
#[derive(Debug, Clone)]
pub struct JsonReply {
data: Vec<u8>,
status_code: StatusCode,
}
impl JsonReply {
pub fn new(data: Vec<u8>) -> Self {
JsonReply {
data,
status_code: StatusCode::OK,
}
}
pub fn with_code(mut self, status_code: StatusCode) -> Self {
self.status_code = status_code;
self
}
}
impl warp::reply::Reply for JsonReply {
#[inline]
fn into_response(self) -> warp::reply::Response {
use warp::http::header::{HeaderValue, CONTENT_TYPE};
let res = warp::reply::Response::new(self.data.into());
let mut res = warp::reply::with_status(res, self.status_code).into_response();
res.headers_mut()
.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
res
}
}
/// Embed block into Block enum
pub fn json_embed_block(value: Vec<u8>) -> JsonReply {
json_embed(&[b"{\"Block\":", &value, b"}"])
}
/// Embed transaction into Transaction enum
pub fn json_embed_transaction(value: Vec<u8>) -> JsonReply {
json_embed(&[b"{\"Transaction\":", &value, b"}"])
}
/// Embed serialized JSON into wrapping JSON
pub fn json_serialize_embed<T: Serialize>(value: T) -> JsonReply {
JsonReply::new(serde_json::to_vec(&value).unwrap_or_default())
}
/// Embed JSON into wrapping JSON
pub fn json_embed(value: &[&[u8]]) -> JsonReply {
JsonReply::new(value.iter().copied().flatten().copied().collect())
}
//====== API RESPONSE HANDLING ======//
/// Call response structure, with handling for errors and ok responses.
#[derive(Debug, Clone)]
pub struct CallResponse<'a> {
pub route: &'a str,
}
impl<'a> CallResponse<'a> {
pub fn new(route: &'a str) -> Self {
CallResponse { route }
}
pub fn into_err_internal(self, api_error_type: ApiErrorType) -> Result<JsonReply, JsonReply> {
self.into_err(StatusCode::INTERNAL_SERVER_ERROR, api_error_type)
}
pub fn into_err_bad_req(self, api_error_type: ApiErrorType) -> Result<JsonReply, JsonReply> {
self.into_err(StatusCode::BAD_REQUEST, api_error_type)
}
pub fn into_err_with_data(
self,
status: StatusCode,
api_error_type: ApiErrorType,
data: JsonReply,
) -> Result<JsonReply, JsonReply> {
Err(common_error_reply(status, api_error_type, self.route, data))
}
pub fn into_err(
self,
status: StatusCode,
api_error_type: ApiErrorType,
) -> Result<JsonReply, JsonReply> {
self.into_err_with_data(status, api_error_type, json_serialize_embed("null"))
}
pub fn into_ok(self, reason: &str, data: JsonReply) -> Result<JsonReply, JsonReply> {
Ok(common_success_reply(self.route, reason, data))
}
}
#[derive(Default, Debug, Serialize)]
pub enum APIResponseStatus {
Success,
Error,
InProgress,
#[default]
Unknown,
}
impl std::fmt::Display for APIResponseStatus {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
APIResponseStatus::Success => write!(f, "Success"),
APIResponseStatus::Error => write!(f, "Error"),
APIResponseStatus::InProgress => write!(f, "InProgress"),
APIResponseStatus::Unknown => write!(f, "Unknown"),
}
}
}
/// Common reply structure for API calls
///
/// ### Arguments
///
/// * `id` - The ID of the API call. Provided by client
/// * `status` - The status of the API call.
/// * `reason` - The reason for the API call's failure, if any
/// * `route` - The route of the API call, as client confirmation
/// * `json_content` - Content of the API call, as JSON
pub fn common_reply(
status: APIResponseStatus,
reason: &str,
route: &str,
content: JsonReply,
) -> JsonReply {
let status = format!("{status}");
json_embed(&[
b"{\"status\":\"",
status.as_bytes(),
b"\",\"reason\":\"",
reason.as_bytes(),
b"\",\"route\":\"",
route.as_bytes(),
b"\",\"content\":",
&content.data,
b"}",
])
}
/// Handles common success replies
///
/// ### Arguments
///
/// * `id` - The ID of the API call. Provided by client
/// * `route` - The route of the API call, as client confirmation
/// * `json_content` - Content of the API call, as JSON
pub fn common_success_reply(route: &str, reason: &str, json_content: JsonReply) -> JsonReply {
common_reply(APIResponseStatus::Success, reason, route, json_content).with_code(StatusCode::OK)
}
/// Handles common error replies
///
/// ### Arguments
///
/// * `id` - The ID of the API call. Provided by client
/// * `error` - The reason for the API call's failure
/// * `route` - The route of the API call, as client confirmation
/// * `json_content` - Content of the API call, as JSON
pub fn common_error_reply(
status: StatusCode,
error_type: ApiErrorType,
route: &str,
data: JsonReply,
) -> JsonReply {
common_reply(
APIResponseStatus::Error,
&format!("{error_type}"),
route,
data,
)
.with_code(status)
}