One error response format: { error, code, details? } (step 1)
- error::ApiError (ResponseError): status + stable snake_case code +
display-safe message + optional details. From<anyhow>/From<diesel> and
into_http_internal_err become a 500 "internal" whose cause is logged,
never sent.
- JSON body, query and path parse failures, the Claims 401 and unknown
routes now answer in the format instead of actix's plain text.
- tags handlers return ApiResult with codes (invalid_tag_name,
tag_not_found, tag_name_taken, no_files, too_many_files,
nothing_to_change, tag_added_and_removed). The rename 409 keeps
existing_tag at the top level for older clients.
- Enhance's error_response builds through ApiError; its codes are
unchanged, and an internal error no longer sends its message.
- duplicates: eight 500s sent format!("{:?}", e) to the client.
Refs #202
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
96a2858a50
commit
13c244765f
7 files changed
+470
-146
No files matched your search
+19
-12
@@ -24,27 +24,34 @@ use super::service::{EnhanceError, EnhanceService, SourceFile};
|
||||
use crate::data::Claims;
|
||||
use crate::database::ExifDao;
|
||||
use crate::database::enhance_dao::{EnhanceJobRow, STATUS_APPROVED, STATUS_READY};
|
||||
use crate::error::ApiError;
|
||||
use crate::libraries::{self, Library};
|
||||
use crate::state::AppState;
|
||||
use crate::utils::normalize_path;
|
||||
use crate::versions::handlers::build_response;
|
||||
use actix_web::ResponseError;
|
||||
|
||||
type ExifData = web::Data<Mutex<Box<dyn ExifDao>>>;
|
||||
|
||||
/// Enhance errors in the shared format (#202). The codes predate it and stay
|
||||
/// as they are: clients may already branch on them.
|
||||
fn error_response(e: &EnhanceError) -> HttpResponse {
|
||||
let (mut builder, code) = match e {
|
||||
EnhanceError::Disabled => (HttpResponse::ServiceUnavailable(), "disabled"),
|
||||
EnhanceError::Unavailable => (HttpResponse::ServiceUnavailable(), "unavailable"),
|
||||
EnhanceError::UnknownTemplate(_) => (HttpResponse::NotFound(), "unknown_template"),
|
||||
EnhanceError::BadRequest(_) => (HttpResponse::BadRequest(), "bad_request"),
|
||||
EnhanceError::Rejected(_) => (HttpResponse::UnprocessableEntity(), "rejected"),
|
||||
EnhanceError::Expired => (HttpResponse::Gone(), "expired"),
|
||||
EnhanceError::NotFound => (HttpResponse::NotFound(), "not_found"),
|
||||
EnhanceError::Unplaceable(_) => (HttpResponse::BadGateway(), "unplaceable"),
|
||||
EnhanceError::Upstream(_) => (HttpResponse::BadGateway(), "upstream"),
|
||||
EnhanceError::Internal(_) => (HttpResponse::InternalServerError(), "internal"),
|
||||
use actix_web::http::StatusCode;
|
||||
let (status, code) = match e {
|
||||
EnhanceError::Disabled => (StatusCode::SERVICE_UNAVAILABLE, "disabled"),
|
||||
EnhanceError::Unavailable => (StatusCode::SERVICE_UNAVAILABLE, "unavailable"),
|
||||
EnhanceError::UnknownTemplate(_) => (StatusCode::NOT_FOUND, "unknown_template"),
|
||||
EnhanceError::BadRequest(_) => (StatusCode::BAD_REQUEST, "bad_request"),
|
||||
EnhanceError::Rejected(_) => (StatusCode::UNPROCESSABLE_ENTITY, "rejected"),
|
||||
EnhanceError::Expired => (StatusCode::GONE, "expired"),
|
||||
EnhanceError::NotFound => (StatusCode::NOT_FOUND, "not_found"),
|
||||
EnhanceError::Unplaceable(_) => (StatusCode::BAD_GATEWAY, "unplaceable"),
|
||||
EnhanceError::Upstream(_) => (StatusCode::BAD_GATEWAY, "upstream"),
|
||||
EnhanceError::Internal(_) => {
|
||||
return ApiError::internal(e).error_response();
|
||||
}
|
||||
};
|
||||
builder.json(json!({ "error": e.message(), "code": code }))
|
||||
ApiError::new(status, code, e.message()).error_response()
|
||||
}
|
||||
|
||||
fn bad(msg: &str) -> HttpResponse {
|
||||
|
||||
Reference in new issue
Block a user