Skip to content

Commit 0bd0979

Browse files
committed
♻️ refactoring
1 parent 90c5b43 commit 0bd0979

File tree

7 files changed

+261
-171
lines changed

7 files changed

+261
-171
lines changed

src/error.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use axum::http::StatusCode;
2+
use axum::response::{IntoResponse, Response};
3+
use axum::Json;
4+
use serde_json::json;
15
use std::fmt;
26

37
pub const EXCEPTION_ERROR_MESSAGE: &str = "An unexpected error occurred.";
@@ -34,3 +38,20 @@ impl fmt::Display for MocksError {
3438
}
3539
}
3640
}
41+
impl IntoResponse for MocksError {
42+
fn into_response(self) -> Response {
43+
let (status, message) = match self {
44+
MocksError::FailedReadFile(err)
45+
| MocksError::FailedWriteFile(err)
46+
| MocksError::InvalidArgs(err)
47+
| MocksError::Exception(err) => (StatusCode::INTERNAL_SERVER_ERROR, err),
48+
MocksError::ResourceNotFound | MocksError::ObjectNotFound => {
49+
(StatusCode::NOT_FOUND, self.to_string())
50+
}
51+
MocksError::MethodNotAllowed => (StatusCode::METHOD_NOT_ALLOWED, self.to_string()),
52+
MocksError::InvalidRequest => (StatusCode::BAD_REQUEST, self.to_string()),
53+
};
54+
55+
(status, Json(json!({ "error": message }))).into_response()
56+
}
57+
}

src/server.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod context;
12
mod handler;
23
mod hc;
34
mod state;
@@ -7,8 +8,6 @@ use crate::server::handler::{delete, get_all, get_one, patch, patch_one, post, p
78
use crate::server::hc::hc;
89
use crate::server::state::{AppState, SharedState};
910
use crate::storage::Storage;
10-
use axum::http::StatusCode;
11-
use axum::response::{IntoResponse, Response};
1211
use axum::routing::get;
1312
use axum::Router;
1413
use serde_json::Value;
@@ -37,7 +36,6 @@ impl Server {
3736
.await
3837
.map_err(|e| MocksError::Exception(e.to_string()))?;
3938

40-
println!();
4139
println!("Endpoints:");
4240
print_endpoints(url, &storage.data);
4341

@@ -70,15 +68,3 @@ fn create_router(state: SharedState) -> Router {
7068
.nest("/:resource", storage_router)
7169
.with_state(state)
7270
}
73-
74-
pub fn response(status_code: StatusCode, body: String) -> Result<impl IntoResponse, StatusCode> {
75-
Response::builder()
76-
.status(status_code)
77-
.header("Content-Type", "application/json")
78-
.body(body)
79-
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
80-
}
81-
82-
pub fn format_err(message: &str) -> String {
83-
format!("{{\"error\": \"{}\"}}", message)
84-
}

src/server/context.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use axum::extract::rejection::JsonRejection;
2+
use axum::extract::FromRequest;
3+
use axum::http::StatusCode;
4+
use axum::{async_trait, Json};
5+
use serde_json::{json, Value};
6+
7+
const INVALID_JSON_REQUEST: &str = "Invalid JSON format in request body.";
8+
9+
#[derive(Debug, Clone, Default)]
10+
pub struct Payload(pub Value);
11+
12+
#[async_trait]
13+
impl<S> FromRequest<S> for Payload
14+
where
15+
S: Send + Sync,
16+
Json<Value>: FromRequest<S, Rejection = JsonRejection>,
17+
{
18+
type Rejection = (StatusCode, Json<Value>);
19+
20+
async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
21+
let Json(value) = Json::<Value>::from_request(req, state)
22+
.await
23+
.map_err(|e| to_rejection(&e.to_string()))?;
24+
25+
if !value.is_object() {
26+
return Err(to_rejection(INVALID_JSON_REQUEST));
27+
}
28+
29+
Ok(Payload(value))
30+
}
31+
}
32+
33+
#[derive(Debug, Clone, Default)]
34+
pub struct PayloadWithId(pub Value);
35+
36+
#[async_trait]
37+
impl<S> FromRequest<S> for PayloadWithId
38+
where
39+
S: Send + Sync,
40+
Json<Value>: FromRequest<S, Rejection = JsonRejection>,
41+
{
42+
type Rejection = (StatusCode, Json<Value>);
43+
44+
async fn from_request(req: axum::extract::Request, state: &S) -> Result<Self, Self::Rejection> {
45+
let Json(value) = Json::<Value>::from_request(req, state)
46+
.await
47+
.map_err(|e| to_rejection(&e.to_string()))?;
48+
49+
if !value.is_object() {
50+
return Err(to_rejection(INVALID_JSON_REQUEST));
51+
}
52+
53+
// ID is required for updates
54+
if value.get("id").is_none() {
55+
return Err(to_rejection("ID is required for updates."));
56+
}
57+
58+
Ok(PayloadWithId(value))
59+
}
60+
}
61+
62+
fn to_rejection(message: &str) -> (StatusCode, Json<Value>) {
63+
let json = Json::from(json!({"error": message}));
64+
(StatusCode::BAD_REQUEST, json)
65+
}

0 commit comments

Comments
 (0)