1use axum::{
7 http::StatusCode,
8 response::{IntoResponse, Response},
9 Json,
10};
11use serde::Serialize;
12use std::sync::Arc;
13
14use crate::{nsupdate::NsupdateExecutor, rndc::RndcExecutor};
15
16#[derive(Clone)]
18pub struct AppState {
19 pub rndc: Arc<RndcExecutor>,
21 pub nsupdate: Arc<NsupdateExecutor>,
23 pub zone_dir: String,
25}
26
27#[derive(Serialize)]
29pub struct ErrorResponse {
30 pub error: String,
31 pub details: Option<String>,
32}
33
34#[derive(Debug, thiserror::Error)]
36pub enum ApiError {
37 #[error("Zone file error: {0}")]
38 ZoneFileError(String),
39
40 #[error("RNDC command failed: {0}")]
41 RndcError(String),
42
43 #[error("Invalid request: {0}")]
44 InvalidRequest(String),
45
46 #[error("Zone not found: {0}")]
47 ZoneNotFound(String),
48
49 #[error("Zone already exists: {0}")]
50 ZoneAlreadyExists(String),
51
52 #[error("Internal server error: {0}")]
53 InternalError(String),
54
55 #[error("Dynamic updates not enabled: {0}")]
56 DynamicUpdatesNotEnabled(String),
57
58 #[error("nsupdate command failed: {0}")]
59 NsupdateError(String),
60
61 #[error("Invalid record: {0}")]
62 InvalidRecord(String),
63}
64
65impl IntoResponse for ApiError {
66 fn into_response(self) -> Response {
67 let (status, error_message) = match &self {
68 ApiError::ZoneFileError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
69 ApiError::RndcError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
70 ApiError::InvalidRequest(_) => (StatusCode::BAD_REQUEST, self.to_string()),
71 ApiError::ZoneNotFound(_) => (StatusCode::NOT_FOUND, self.to_string()),
72 ApiError::ZoneAlreadyExists(_) => (StatusCode::CONFLICT, self.to_string()),
73 ApiError::InternalError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
74 ApiError::DynamicUpdatesNotEnabled(_) => (StatusCode::BAD_REQUEST, self.to_string()),
75 ApiError::NsupdateError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
76 ApiError::InvalidRecord(_) => (StatusCode::BAD_REQUEST, self.to_string()),
77 };
78
79 let body = Json(ErrorResponse {
80 error: error_message,
81 details: None,
82 });
83
84 (status, body).into_response()
85 }
86}