aboutsummaryrefslogtreecommitdiff
path: root/src/response
diff options
context:
space:
mode:
Diffstat (limited to 'src/response')
-rw-r--r--src/response/error.rs69
-rw-r--r--src/response/mod.rs70
-rw-r--r--src/response/success.rs33
3 files changed, 172 insertions, 0 deletions
diff --git a/src/response/error.rs b/src/response/error.rs
new file mode 100644
index 0000000..db39da8
--- /dev/null
+++ b/src/response/error.rs
@@ -0,0 +1,69 @@
1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4};
5use serde::Serialize;
6use utoipa::ToSchema;
7
8use crate::ApiError;
9
10#[derive(Serialize, ToSchema)]
11#[schema(examples("fail or error"))]
12enum ErrorStatus {
13 #[serde(rename = "fail")]
14 Fail,
15 #[serde(rename = "error")]
16 Error,
17}
18
19#[derive(Serialize, ToSchema)]
20pub struct ErrorResponse {
21 status: ErrorStatus,
22 #[schema(examples("SomeErrorKind", "NotAuthorized", "Database"))]
23 kind: String,
24 #[schema(examples("some error text"))]
25 message: String,
26}
27
28impl ErrorResponse {
29 pub fn fail(kind: impl Into<String>, message: impl Into<String>) -> Self {
30 Self {
31 status: ErrorStatus::Fail,
32 kind: kind.into(),
33 message: message.into(),
34 }
35 }
36
37 pub fn error(kind: impl Into<String>, message: impl Into<String>) -> Self {
38 Self {
39 status: ErrorStatus::Error,
40 kind: kind.into(),
41 message: message.into(),
42 }
43 }
44}
45
46impl IntoResponse for ErrorResponse {
47 fn into_response(self) -> Response {
48 (
49 match self.status {
50 ErrorStatus::Fail => StatusCode::BAD_REQUEST,
51 ErrorStatus::Error => StatusCode::INTERNAL_SERVER_ERROR,
52 },
53 axum::Json(self),
54 )
55 .into_response()
56 }
57}
58
59impl<T> From<T> for ErrorResponse
60where
61 T: Into<ApiError>,
62{
63 fn from(value: T) -> Self {
64 match value.into() {
65 ApiError::Client(e) => Self::fail(e.kind(), e.into_message()),
66 ApiError::Server(e) => Self::fail(e.kind(), e.into_message()),
67 }
68 }
69}
diff --git a/src/response/mod.rs b/src/response/mod.rs
new file mode 100644
index 0000000..166bc13
--- /dev/null
+++ b/src/response/mod.rs
@@ -0,0 +1,70 @@
1mod error;
2mod success;
3
4pub use error::ErrorResponse;
5use serde_json::json;
6pub use success::SuccessResponse;
7
8use std::collections::BTreeMap;
9
10use utoipa::{
11 IntoResponses, ToSchema,
12 openapi::{
13 ContentBuilder, RefOr, ResponseBuilder, ResponsesBuilder, example::ExampleBuilder,
14 response::Response, schema::RefBuilder,
15 },
16};
17
18pub type ApiResult<T> = Result<SuccessResponse<T>, ErrorResponse>;
19
20pub struct GlobalResponses;
21
22impl IntoResponses for GlobalResponses {
23 fn responses() -> BTreeMap<String, RefOr<Response>> {
24 ResponsesBuilder::new()
25 .response(
26 "400",
27 ResponseBuilder::new()
28 .content(
29 "application/json",
30 ContentBuilder::new()
31 .schema(Some(
32 RefBuilder::new()
33 .ref_location_from_schema_name(ErrorResponse::name()),
34 ))
35 .examples_from_iter([(
36 "Fail",
37 ExampleBuilder::new().value(Some(json!(ErrorResponse::fail(
38 "SomeFailKind",
39 "some fail message"
40 )))),
41 )])
42 .build(),
43 )
44 .description("General response for invalid request"),
45 )
46 .response(
47 "500",
48 ResponseBuilder::new()
49 .content(
50 "application/json",
51 ContentBuilder::new()
52 .schema(Some(
53 RefBuilder::new()
54 .ref_location_from_schema_name(ErrorResponse::name()),
55 ))
56 .examples_from_iter([(
57 "Error",
58 ExampleBuilder::new().value(Some(json!(ErrorResponse::error(
59 "SomeErrorKind",
60 "some error message"
61 )))),
62 )])
63 .build(),
64 )
65 .description("General response when a server error occurs"),
66 )
67 .build()
68 .into()
69 }
70}
diff --git a/src/response/success.rs b/src/response/success.rs
new file mode 100644
index 0000000..c2ec4e5
--- /dev/null
+++ b/src/response/success.rs
@@ -0,0 +1,33 @@
1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4};
5use serde::Serialize;
6use utoipa::ToSchema;
7
8#[derive(Serialize, ToSchema)]
9enum SuccessStatus {
10 #[serde(rename = "success")]
11 Success,
12}
13
14#[derive(Serialize, ToSchema)]
15pub struct SuccessResponse<T> {
16 status: SuccessStatus,
17 data: T,
18}
19
20impl<T> SuccessResponse<T> {
21 pub fn ok(data: T) -> Self {
22 Self {
23 status: SuccessStatus::Success,
24 data,
25 }
26 }
27}
28
29impl<T: Serialize> IntoResponse for SuccessResponse<T> {
30 fn into_response(self) -> Response {
31 (StatusCode::OK, axum::Json(self)).into_response()
32 }
33}