limiting_factor_axum/api/
replies.rs

1/*  -------------------------------------------------------------
2    Limiting Factor :: axum :: API :: replies
3    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4    Project:        Nasqueron
5    License:        BSD-2-Clause
6    -------------------------------------------------------------    */
7
8//! # API standard and JSON responses.
9//!
10//! This module provides useful traits and methods to craft API replies from an existing type.
11
12use axum::http::StatusCode;
13use axum::Json;
14
15#[cfg(feature = "serialization")]
16use serde::Serialize;
17
18/*  -------------------------------------------------------------
19    JSON responses
20    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    */
21
22pub type ApiJsonResponse<T> = Result<Json<T>, (StatusCode, Json<String>)>;
23
24/// This trait allows to consume an object into an HTTP response.
25pub trait ApiResponse<T> {
26    /// Consumes the value and creates a JSON or a Status result response.
27    fn into_json_response(self) -> ApiJsonResponse<T>;
28}
29
30impl<T> ApiResponse<T> for Json<T> {
31    fn into_json_response(self) -> ApiJsonResponse<T> {
32        Ok(self)
33    }
34}
35
36#[cfg(feature = "serialization")]
37impl<T> ApiResponse<T> for T where T: Serialize {
38    fn into_json_response(self) -> ApiJsonResponse<T> {
39        Ok(Json(self))
40    }
41}
42
43//  -------------------------------------------------------------
44//  Failures
45//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46
47pub trait FailureResponse {
48    fn status_code(&self) -> StatusCode;
49
50    fn response(&self) -> String;
51}
52
53impl FailureResponse for StatusCode {
54    fn status_code(&self) -> StatusCode {
55        self.clone()
56    }
57
58    fn response(&self) -> String {
59        self.canonical_reason().unwrap_or_default().to_string()
60    }
61}
62
63impl<T, E> ApiResponse<T> for Result<T, E>
64    where T: ApiResponse<T>, E: FailureResponse
65{
66    fn into_json_response(self) -> ApiJsonResponse<T> {
67        match self {
68            Ok(value) => value.into_json_response(),
69            Err(error) => Err((error.status_code(), Json(error.response())))
70        }
71    }
72}