fix(api): return the generic AppError envelope for extractor errors #479

Merged
nrupard merged 1 commit from fix/BUNYIP-481-extractor-error-handlers into main 2026-08-05 21:49:54 +02:00
Owner

What

New bunyip-api/src/extractors.rs gives the Json / Path / Query / Form extractor configs a generic error_handler, wired into App::new(). A malformed request body or a bad path/query/form parameter now returns the standard AppError envelope ({ success:false, error:{ code, message }, meta:{ request_id } }) with a generic message, instead of actix's default raw parse text. The real parse error is logged via tracing::warn!(extractor, error).

  • JSON / form body -> The request body was malformed or invalid.
  • path / query -> Invalid request.
  • json_config() keeps the existing 32 KB limit.

Why (BUNYIP-481)

Only JsonConfig was registered (size limit, no handler) and Path/Query/Form used actix defaults, so the 149 extractor sites could echo framework parse detail (field names, ... at line 1 column 20) to direct API callers, bypassing the AppError envelope every other error uses. Same invariant as BUNYIP-477; this is the direct-API-caller counterpart (the browser BFF was already insulated - bunyip-web reads only error.message, which is absent from actix's default body).

Coverage

Extractor Sites Config
web::Json 60 json_config() (32 KB limit + handler)
web::Path 65 path_config()
web::Query 22 query_config()
web::Form 2 form_config()

Test

malformed_json_returns_generic_envelope_no_parse_detail: a malformed JSON body returns status 400 with error.code == BAD_REQUEST, the generic message, a string meta.request_id, and no expected / deserialize parse tells. just check-container green (fmt + clippy + full workspace, bunyip-api 111 tests).

#BUNYIP-481

## What New `bunyip-api/src/extractors.rs` gives the Json / Path / Query / Form extractor configs a generic `error_handler`, wired into `App::new()`. A malformed request body or a bad path/query/form parameter now returns the standard `AppError` envelope (`{ success:false, error:{ code, message }, meta:{ request_id } }`) with a generic message, instead of actix's default raw parse text. The real parse error is logged via `tracing::warn!(extractor, error)`. - JSON / form body -> `The request body was malformed or invalid.` - path / query -> `Invalid request.` - `json_config()` keeps the existing 32 KB limit. ## Why (BUNYIP-481) Only `JsonConfig` was registered (size limit, no handler) and Path/Query/Form used actix defaults, so the 149 extractor sites could echo framework parse detail (field names, `... at line 1 column 20`) to direct API callers, bypassing the `AppError` envelope every other error uses. Same invariant as BUNYIP-477; this is the direct-API-caller counterpart (the browser BFF was already insulated - bunyip-web reads only `error.message`, which is absent from actix's default body). ## Coverage | Extractor | Sites | Config | |---|---|---| | `web::Json` | 60 | `json_config()` (32 KB limit + handler) | | `web::Path` | 65 | `path_config()` | | `web::Query` | 22 | `query_config()` | | `web::Form` | 2 | `form_config()` | ## Test `malformed_json_returns_generic_envelope_no_parse_detail`: a malformed JSON body returns status 400 with `error.code == BAD_REQUEST`, the generic message, a string `meta.request_id`, and no `expected` / `deserialize` parse tells. `just check-container` green (fmt + clippy + full workspace, bunyip-api 111 tests). #BUNYIP-481
fix(api): return the generic AppError envelope for extractor errors
All checks were successful
E2E PR gate / Install + reachability (no deployment secrets) (pull_request) Successful in 23s
Check / fmt + clippy + build + tests (pull_request) Successful in 4m41s
Create release / Create release from merged PR (pull_request) Has been skipped
28e557952f
Add bunyip-api/src/extractors.rs with generic error_handlers for the Json / Path / Query / Form extractor configs and wire all four into App::new(). A malformed request body or a bad path / query / form parameter now returns the standard AppError envelope with a generic message ("The request body was malformed or invalid." / "Invalid request.") and a request_id, instead of actix's default raw parse text (field names, parse positions). The real parse error is logged via tracing::warn!(extractor, error) so diagnosis is unaffected.

Before this, only JsonConfig was registered (size limit, no error handler) and Path / Query / Form used actix defaults, so the 149 extractor sites could echo framework parse detail to direct API callers, bypassing the envelope every other error uses. The browser BFF was already insulated (bunyip-web reads only error.message, absent from actix's default body); this covers direct API and OAuth clients. Sibling to the browser-facing fix in BUNYIP-477.

Test: a malformed JSON body returns status 400 with the generic envelope (code BAD_REQUEST, generic message, request_id) and none of actix's parse tells.

#BUNYIP-481
nrupard deleted branch fix/BUNYIP-481-extractor-error-handlers 2026-08-05 21:49:54 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!479
No description provided.