feat: implement filament and spool preset services with CRUD operations
- Add `FilamentService` for managing filament inventory, including creation, retrieval, updating, and deletion of filaments. - Introduce `SpoolPresetService` for handling spool presets, allowing users to create, update, and delete their custom presets. - Create domain models for `Filament` and `SpoolPreset` with necessary fields and methods. - Define repository interfaces for filament and spool preset persistence. - Implement application configuration management from environment variables. - Set up error handling with a centralized `AppError` type. - Build the Axum router with public and protected routes for user authentication and resource management.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
/// Erro centralizado da aplicação.
|
||||
/// Toda camada retorna `Result<T, AppError>`.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AppError {
|
||||
#[error("not found")]
|
||||
NotFound,
|
||||
|
||||
#[error("unauthorized")]
|
||||
Unauthorized,
|
||||
|
||||
#[error("forbidden")]
|
||||
Forbidden,
|
||||
|
||||
#[error("validation error: {0}")]
|
||||
Validation(String),
|
||||
|
||||
#[error("conflict: {0}")]
|
||||
Conflict(String),
|
||||
|
||||
#[error("unprocessable entity: {0}")]
|
||||
UnprocessableEntity(String),
|
||||
|
||||
#[error("internal error")]
|
||||
Internal(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
fn status_and_code(&self) -> (StatusCode, &'static str) {
|
||||
match self {
|
||||
Self::NotFound => (StatusCode::NOT_FOUND, "NOT_FOUND"),
|
||||
Self::Unauthorized => (StatusCode::UNAUTHORIZED, "UNAUTHORIZED"),
|
||||
Self::Forbidden => (StatusCode::FORBIDDEN, "FORBIDDEN"),
|
||||
Self::Validation(_) => (StatusCode::BAD_REQUEST, "VALIDATION_ERROR"),
|
||||
Self::Conflict(_) => (StatusCode::CONFLICT, "CONFLICT"),
|
||||
Self::UnprocessableEntity(_) => (StatusCode::UNPROCESSABLE_ENTITY, "UNPROCESSABLE_ENTITY"),
|
||||
Self::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL_ERROR"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, code) = self.status_and_code();
|
||||
|
||||
if status == StatusCode::INTERNAL_SERVER_ERROR {
|
||||
tracing::error!(error = %self, "Internal server error");
|
||||
}
|
||||
|
||||
let body = Json(json!({
|
||||
"error": self.to_string(),
|
||||
"code": code,
|
||||
}));
|
||||
|
||||
(status, body).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for AppError {
|
||||
fn from(err: sqlx::Error) -> Self {
|
||||
match err {
|
||||
sqlx::Error::RowNotFound => Self::NotFound,
|
||||
_ => Self::Internal(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<validator::ValidationErrors> for AppError {
|
||||
fn from(err: validator::ValidationErrors) -> Self {
|
||||
Self::Validation(err.to_string())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user