Skip to main content

systemprompt_api/error/
conversions.rs

1//! `From` impls mapping domain, repository, and service errors onto
2//! [`ApiHttpError`], keeping the variant-to-HTTP-status mapping in one place so
3//! non-OAuth handlers use `?`. `RepositoryError` and `ServiceError` already
4//! classify into [`ApiError`] in `systemprompt-models`; those impls are reused
5//! here. The umbrella domain errors are classified by variant so that, e.g., a
6//! repository failure surfaces as 500 while a missing entity surfaces as 404.
7
8use systemprompt_agent::{AgentError, ProtocolError};
9use systemprompt_marketplace::MarketplaceError;
10use systemprompt_models::api::ApiError;
11use systemprompt_models::errors::ServiceError;
12use systemprompt_traits::RepositoryError;
13use systemprompt_users::UserError;
14
15use super::ApiHttpError;
16
17impl From<RepositoryError> for ApiHttpError {
18    fn from(err: RepositoryError) -> Self {
19        Self(ApiError::from(err))
20    }
21}
22
23impl From<ServiceError> for ApiHttpError {
24    fn from(err: ServiceError) -> Self {
25        Self(ApiError::from(err))
26    }
27}
28
29impl From<AgentError> for ApiHttpError {
30    fn from(err: AgentError) -> Self {
31        let api = match err {
32            AgentError::NotFound(msg) => ApiError::not_found(msg),
33            AgentError::Validation(msg)
34            | AgentError::Protocol(ProtocolError::ValidationFailed(msg)) => {
35                ApiError::bad_request(msg)
36            },
37            other => ApiError::internal_error(other.to_string()),
38        };
39        Self(api)
40    }
41}
42
43impl From<MarketplaceError> for ApiHttpError {
44    fn from(err: MarketplaceError) -> Self {
45        let api = match &err {
46            MarketplaceError::NotFound(_) | MarketplaceError::NoDefault => {
47                ApiError::not_found(err.to_string())
48            },
49            MarketplaceError::Validation(_) => ApiError::bad_request(err.to_string()),
50            MarketplaceError::Catalog(_)
51            | MarketplaceError::Signing(_)
52            | MarketplaceError::Filter(_) => ApiError::internal_error(err.to_string()),
53        };
54        Self(api)
55    }
56}
57
58impl From<UserError> for ApiHttpError {
59    fn from(err: UserError) -> Self {
60        let message = err.to_string();
61        let api = match err {
62            UserError::Repository(inner) => ApiError::from(RepositoryError::from(inner)),
63            UserError::NotFound(_) => ApiError::not_found(message),
64            UserError::EmailAlreadyExists(_) => ApiError::conflict(message),
65            UserError::Validation(_)
66            | UserError::InvalidStatus(_)
67            | UserError::InvalidRole(_)
68            | UserError::InvalidRoles(_) => ApiError::bad_request(message),
69            UserError::Pool(_) => ApiError::internal_error(message),
70        };
71        Self(api)
72    }
73}