Skip to main content

molten_api/
error.rs

1//! Contains error types and their HTTP response conversions for the Molten API.
2//!
3//! This module defines `ApiError` for handling various application-specific errors
4//! originating from service and configuration layers, converting them into
5//! appropriate HTTP status codes and JSON responses. It also includes `BuildError`
6//! for errors encountered during application startup.
7use axum::{
8    Json,
9    http::StatusCode,
10    response::{IntoResponse, Response},
11};
12use molten_config::ConfigError;
13use molten_service::ServiceError;
14use serde_json::json;
15use thiserror::Error;
16
17/// A wrapper to allow us to implement Http responses for the API
18#[derive(Error, Debug)]
19pub enum ApiError {
20    /// Errors generated from calling molten-service functions
21    #[error("molten-service error: {0:?}")]
22    Service(#[from] ServiceError),
23    /// Errors generated from calling molten-config functions
24    #[error("molten-config error: {0:?}")]
25    Config(#[from] ConfigError),
26}
27
28impl IntoResponse for ApiError {
29    fn into_response(self) -> Response {
30        let (status, message) = match &self {
31            // 404 Not Found
32            ApiError::Service(ServiceError::FormNotFound(id)) => {
33                (StatusCode::NOT_FOUND, format!("Form '{}' not found", id))
34            }
35            ApiError::Service(ServiceError::WorkflowNotFound(id)) => (
36                StatusCode::NOT_FOUND,
37                format!("Workflow '{}' not found", id),
38            ),
39
40            // 400 Bad Request (Validation)
41            ApiError::Service(ServiceError::DocumentValidationErrors(errs)) => {
42                // Return the detailed list of validation failures
43                return (
44                    StatusCode::BAD_REQUEST,
45                    Json(json!({ "error": "Document Validation Failed", "details": errs })),
46                )
47                    .into_response();
48            }
49            ApiError::Service(ServiceError::FormValidationErrors(e)) => {
50                (StatusCode::BAD_REQUEST, e.to_string())
51            }
52            ApiError::Service(ServiceError::WorkflowValidationErrors(e)) => {
53                (StatusCode::BAD_REQUEST, e.to_string())
54            }
55            ApiError::Config(ConfigError::ValidationErrors(e)) => {
56                (StatusCode::BAD_REQUEST, e.to_string())
57            }
58            ApiError::Service(ServiceError::WorkflowRuleViolation(e)) => {
59                (StatusCode::BAD_REQUEST, e.to_string())
60            }
61            ApiError::Config(ConfigError::JsonError(e)) => (StatusCode::BAD_REQUEST, e.to_string()),
62
63            // 500 Internal Server Error
64            ApiError::Service(ServiceError::DatabaseError(e)) => {
65                (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
66            }
67            ApiError::Service(ServiceError::Internal(e)) => {
68                (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
69            }
70            ApiError::Config(e) => {
71                tracing::error!("Unhandled ConfigError in API layer: {:?}", e);
72                return (
73                    StatusCode::INTERNAL_SERVER_ERROR,
74                    Json(json!({ "error": "Internal server error" })),
75                )
76                    .into_response();
77            }
78        };
79
80        (status, Json(json!({ "error": message }))).into_response()
81    }
82}
83
84/// Represents errors that can occur during the API server's startup phase.
85/// These errors typically relate to database connection issues or I/O operations
86/// essential for initializing the application.
87#[derive(Debug, Error)]
88pub enum BuildError {
89    /// Errors generated during startup from database operations
90    #[error("database error during startup")]
91    Database(#[from] sea_orm::DbErr),
92
93    /// Errors generated during startup from running the application
94    #[error("I/O error during startup")]
95    Io(#[from] std::io::Error),
96}