fraiseql_server/routes/api/
types.rs1use std::fmt;
4
5use axum::{
6 Json,
7 http::StatusCode,
8 response::{IntoResponse, Response},
9};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Serialize, Deserialize, Clone)]
14pub struct ApiError {
15 pub error: String,
17 pub code: String,
19 pub details: Option<String>,
21}
22
23impl ApiError {
24 pub fn new(error: impl Into<String>, code: impl Into<String>) -> Self {
26 Self {
27 error: error.into(),
28 code: code.into(),
29 details: None,
30 }
31 }
32
33 pub fn with_details(mut self, details: impl Into<String>) -> Self {
35 self.details = Some(details.into());
36 self
37 }
38
39 pub fn parse_error(msg: impl fmt::Display) -> Self {
41 Self::new(format!("Parse error: {}", msg), "PARSE_ERROR")
42 }
43
44 pub fn validation_error(msg: impl fmt::Display) -> Self {
46 Self::new(format!("Validation error: {}", msg), "VALIDATION_ERROR")
47 }
48
49 pub fn internal_error(msg: impl fmt::Display) -> Self {
51 Self::new(format!("Internal server error: {}", msg), "INTERNAL_ERROR")
52 }
53
54 pub fn unauthorized() -> Self {
56 Self::new("Unauthorized", "UNAUTHORIZED")
57 }
58
59 pub fn not_found(msg: impl fmt::Display) -> Self {
61 Self::new(format!("Not found: {}", msg), "NOT_FOUND")
62 }
63}
64
65impl fmt::Display for ApiError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "{}: {}", self.code, self.error)
68 }
69}
70
71impl IntoResponse for ApiError {
72 fn into_response(self) -> Response {
73 let status = match self.code.as_str() {
74 "UNAUTHORIZED" => StatusCode::UNAUTHORIZED,
75 "FORBIDDEN" => StatusCode::FORBIDDEN,
76 "NOT_FOUND" => StatusCode::NOT_FOUND,
77 "VALIDATION_ERROR" | "PARSE_ERROR" => StatusCode::BAD_REQUEST,
78 "SERVICE_UNAVAILABLE" => StatusCode::SERVICE_UNAVAILABLE,
79 _ => StatusCode::INTERNAL_SERVER_ERROR,
80 };
81
82 (status, Json(self)).into_response()
83 }
84}
85
86#[derive(Debug, Serialize, Deserialize)]
88pub struct ApiResponse<T> {
89 pub status: String,
91 pub data: T,
93}
94
95impl<T: Serialize> ApiResponse<T> {
96 pub fn success(data: T) -> Json<Self> {
98 Json(Self {
99 status: "success".to_string(),
100 data,
101 })
102 }
103}
104
105#[derive(Debug, Serialize, Deserialize, Clone)]
110pub struct SanitizedConfig {
111 pub port: u16,
113
114 pub host: String,
116
117 pub workers: Option<usize>,
119
120 pub tls_enabled: bool,
122
123 pub sanitized: bool,
125}
126
127impl SanitizedConfig {
128 pub fn from_config(config: &crate::config::HttpServerConfig) -> Self {
135 Self {
136 port: config.port,
137 host: config.host.clone(),
138 workers: config.workers,
139 tls_enabled: config.tls.is_some(),
140 sanitized: true,
141 }
142 }
143
144 pub const fn is_sanitized(&self) -> bool {
146 self.sanitized
147 }
148}