puerto 0.13.0

Puerto — Rust full-stack DDD framework CLI. Scaffolds Clean Architecture projects with auto-wired DI, SQLx support, and zero manual wiring. Formerly puerto-framework.
{% import "presentation/macros.tera" as macros %}use business::domain::{{ snake }}::errors::{{ pascal }}Error;
use poem::http::StatusCode;
use poem_openapi::payload::Json;

use crate::api::error::{ErrorResponse, IntoErrorResponse};

impl IntoErrorResponse for {{ pascal }}Error {
    /// Exhaustive on purpose: a new error variant does not compile until it has a status.
    fn into_error_response(self) -> (StatusCode, Json<ErrorResponse>) {
        let status = match &self {
            {{ pascal }}Error::ValidationError(_) => StatusCode::UNPROCESSABLE_ENTITY,
            {{ pascal }}Error::NotFound => StatusCode::NOT_FOUND,
            {{ pascal }}Error::Duplicate => StatusCode::CONFLICT,
            {{ pascal }}Error::RepositoryError => StatusCode::INTERNAL_SERVER_ERROR,
            {{ pascal }}Error::Unknown => StatusCode::INTERNAL_SERVER_ERROR,{% for v in vos %}
            {{ pascal }}Error::Invalid{{ v.vo }} => StatusCode::UNPROCESSABLE_ENTITY,{% endfor %}
        };
        (status, Json(ErrorResponse::from_code(self.to_string())))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
{# One test per arm, so a status cannot drift unnoticed. -#}
{{ macros::error_case(name="should_map_validation_error_to_422_with_its_code", error=pascal ~ 'Error::ValidationError("name_empty".into())', status="UNPROCESSABLE_ENTITY", code=snake ~ ".validation_error.name_empty") }}
{{- macros::error_case(name="should_map_not_found_to_404_with_its_code", error=pascal ~ "Error::NotFound", status="NOT_FOUND", code=snake ~ ".not_found") }}
{{- macros::error_case(name="should_map_duplicate_to_409_with_its_code", error=pascal ~ "Error::Duplicate", status="CONFLICT", code=snake ~ ".duplicate") }}
{{- macros::error_case(name="should_map_repository_error_to_500_with_its_code", error=pascal ~ "Error::RepositoryError", status="INTERNAL_SERVER_ERROR", code=snake ~ ".repository_error") }}
{{- macros::error_case(name="should_map_unknown_to_500_with_its_code", error=pascal ~ "Error::Unknown", status="INTERNAL_SERVER_ERROR", code=snake ~ ".unknown") }}
{%- for v in vos %}{{ macros::error_case(name="should_map_invalid_" ~ v.vo_snake ~ "_to_422_with_its_code", error=pascal ~ "Error::Invalid" ~ v.vo, status="UNPROCESSABLE_ENTITY", code=snake ~ ".invalid_" ~ v.vo_snake) }}{% endfor %}}