Skip to main content

monster_service/
error.rs

1use axum::{
2    http::StatusCode,
3    response::{IntoResponse, Response},
4};
5use edda_types::{monster::MonsterError, rules_text::RulesTextError};
6
7/// What a request can fail with, and the status it answers.
8#[derive(Debug, thiserror::Error)]
9pub enum ApiError {
10    #[error("not found")]
11    NotFound,
12    /// The shared library is changed by importing, not through the API.
13    #[error("the shared library can't be changed here; make a copy for the campaign instead")]
14    Shared,
15    /// The campaign keeps as many as it may.
16    #[error("{0}")]
17    Limit(String),
18    /// Only the DM's devices change the campaign's monsters, spells and
19    /// conditions.
20    #[error("only a DM device can change the campaign's monsters, spells and conditions")]
21    DmOnly,
22    /// Not what was asked for, as an export of another campaign.
23    #[error("{0}")]
24    BadRequest(String),
25    /// Something's in the way, as a campaign's own of an import.
26    #[error("{0}")]
27    Conflict(String),
28    #[error(transparent)]
29    Invalid(#[from] MonsterError),
30    #[error(transparent)]
31    InvalidText(#[from] RulesTextError),
32    #[error("database error: {0}")]
33    Database(#[from] sqlx::Error),
34    #[error("corrupt stored data: {0}")]
35    Corrupt(String),
36}
37
38impl IntoResponse for ApiError {
39    fn into_response(self) -> Response {
40        let status = match &self {
41            ApiError::NotFound => StatusCode::NOT_FOUND,
42            ApiError::BadRequest(_) => StatusCode::BAD_REQUEST,
43            ApiError::Conflict(_) => StatusCode::CONFLICT,
44            ApiError::Shared | ApiError::DmOnly | ApiError::Limit(_) => StatusCode::FORBIDDEN,
45            ApiError::Invalid(_) | ApiError::InvalidText(_) => StatusCode::UNPROCESSABLE_ENTITY,
46            ApiError::Database(_) | ApiError::Corrupt(_) => StatusCode::INTERNAL_SERVER_ERROR,
47        };
48        edda_server::error_response(status, &self)
49    }
50}