feat(form-builder): standardised error envelope for public form API (D6)
S2c D6. Seven concrete exceptions over a shared PublicFormApiException
base + a single renderer in bootstrap/app.php produce the contract:
{ "message": "...", "code": "...", "errors"?: {...} }
Codes: SCHEMA_NOT_FOUND (404), TOKEN_EXPIRED (410), TOKEN_REVOKED (410),
SCHEMA_UNPUBLISHED (410), SUBMISSION_ALREADY_SUBMITTED (409),
RATE_LIMITED (429 with Retry-After header), VALIDATION_FAILED (422
with per-field errors).
Used by PublicFormController (resolve) and PublicFormSubmissionController
(load/submit lifecycle). Every public-form endpoint now emits the same
envelope regardless of which branch failed; the renderer only fires on
PublicFormApiException so the authenticated API still uses its default
Laravel shapes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,19 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
// Public Form Builder standardised error envelope (S2c D6).
|
||||
$exceptions->render(function (\App\Exceptions\FormBuilder\PublicFormApiException $e, Request $request) {
|
||||
$body = [
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->publicCode,
|
||||
];
|
||||
if ($e->fieldErrors !== null) {
|
||||
$body['errors'] = $e->fieldErrors;
|
||||
}
|
||||
|
||||
return response()->json($body, $e->status, $e->headers);
|
||||
});
|
||||
|
||||
// Database connection / query errors → 503
|
||||
$exceptions->render(function (QueryException|PDOException $e, Request $request) {
|
||||
if ($request->expectsJson() || $request->is('api/*')) {
|
||||
|
||||
Reference in New Issue
Block a user