refactor(server): consolidate handler error boilerplate into crate::error (#83) #104
No reviewers
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom!104
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/83-apierror"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Kills the error-handling duplication called out in #83. Every resource module had its own copy of
struct ErrorBody,type ApiResult<T>, andbad_request/not_found/forbidden/conflict/internal/storage_err.New
crate::error:ApiError { status, message }—IntoResponserenders the same{ "error": msg }body as before;From<StorageError>applies the canonical mapping (NotFound→404, Conflict→409, else→500 — exactly what everystorage_errdid), so handlers can?storage calls directly.pub type ApiResult<T> = Result<Json<T>, ApiError>.bad_request("x"),.map_err(internal),.map_err(storage_err),.ok_or_else(|| not_found(..))— are textually unchanged.Migrated all 10 handler modules. Module-specific statuses (422 unprocessable, 410 gone, avatar errors) keep a tiny local helper that now returns
ApiError.Net −313 lines. No status code or response body changes — verified by the full existing suite.
Verification
cargo test -p server— 130 passed.cargo clippy -p server --all-targets -- -D warnings— clean.Deliberately out of scope (follow-up)
ChannelMemberextractor (second bullet of #83): it only fits routes with a:channel_idpath segment, whereas reactions/threads derive the channel from a message/thread id — so it deserves its own focused change rather than being forced here.AuthRejection,PermissionRejection, gateway handler) are a separate pattern and left as-is.Part of #83
Every resource module redeclared an identical `struct ErrorBody`, an `ApiResult<T>` alias, and the same `bad_request`/`not_found`/`forbidden`/ `conflict`/`internal`/`storage_err` constructors. Promote them once to `crate::error`: - `ApiError { status, message }` implements `IntoResponse` (same `{ "error": msg }` body as before) and `From<StorageError>` (NotFound→404, Conflict→409, else→500 — the old `storage_err` mapping), so handlers can use `?` on storage calls directly. - `pub type ApiResult<T> = Result<Json<T>, ApiError>`. - Free functions with the old names/behavior are kept, so call sites (`bad_request("x")`, `.map_err(internal)`, `.map_err(storage_err)`) are unchanged. Migrated all 10 handler modules (attachments, auth, channels, invites, membership, messages, profiles, reactions, roles, threads) to the shared type. Module-specific statuses (422 unprocessable, 410 gone, avatar errors) keep a small local helper now returning `ApiError`. Net −313 lines. No response status/body changes. Not included here: the `ChannelMember` extractor (the second bullet of #83) — it only fits routes with a `:channel_id` path segment, while reactions/threads derive the channel indirectly, so it warrants its own focused change. The extractor-rejection types (`AuthRejection`, `PermissionRejection`) are left as their own concern. Part of #83 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>