jenky/api-error
jenky/api-error is a Laravel/PHP package for consistent API error handling, helping developers return structured JSON error responses and manage exceptions cleanly across API endpoints with less repetitive boilerplate.
composer require jenky/api-error and pin to ^0.3 for now. Confirm what you actually installed with composer show jenky/api-error — 0.3.1 is a patch release with no published notes beyond the compare link, so there is nothing new to learn beyond 0.3.0.php artisan api-error:install per the README; fall back to vendor:publish if your version exposes tags instead). This gives you config/api-error.php, which is the single source of truth for error codes, HTTP status codes, and messages.config/api-error.php, and src/ApiError.php / src/Exception/ApiErrorException.php to learn the exact factory and constructor signatures. The package's tests/ directory is the best source of canonical examples if the README is thin.response()->json(['error' => 'Not found'], 404) with a configured error code, throw the package exception from your action/service, and let a single renderer in app/Exceptions/Handler.php produce the JSON envelope. That gives every endpoint the same error shape on day one.code field. This becomes your regression net for every later bump.auth.*, user.*, billing.*) in config/api-error.php. Each entry should carry a stable machine-readable code, an http_code, a human message, and optional description/help. Treat this file like a public API contract — it is reviewed in PRs.ApiError via its factory); controllers stay free of response-formatting code. This keeps the envelope identical whether the error originates in a job, a controller, or a middleware.Handler::register()/render(), map Laravel's built-ins to your codes: validation → 422, unauthenticated → 401, authorization → 403, ModelNotFoundException → 404, throttling → 429. API clients should never see Laravel's default shape on one route and your envelope on another.ApiErrorResponse::make(ApiError::fromCode(...)) directly. Same shape, no exception plumbing.code language-independent and resolve message/description through translation files. This lets the frontend switch on code while users see localised copy.config('api-error.error_codes') and asserts every code is unique and every http_code is a valid 4xx/5xx. Duplicate codes are the most common silent failure in this style of package.php artisan config:cache in your deploy smoke test. It catches non-serialisable config values and stale catalogs in one step.0.3.*, read the compare link (and CHANGELOG/git log if the notes are empty) before every minor bump, and keep the package behind a thin App\Exceptions\ApiException wrapper so a future swap is a one-file change.config/api-error.php has no effect until php artisan config:clear (local) or a fresh config:cache (deploy). If a new code returns a 500, check this first.code; whichever wins depends on load order. Enforce uniqueness with the test above.404 for something that should be 422, or 200 for an error. Keep 4xx for client faults, 5xx for server faults, and review the http_code column in code review.app.debug. In production the envelope should carry code, message, and optionally help — never stack traces or SQL.expectsJson() matters. If a request doesn't send Accept: application/json, Laravel may take the HTML path and bypass your renderer. Assert the content type in tests and document the required header for consumers.code, renaming it is a breaking change even though the package version says "patch". Version your envelope deliberately and add fields rather than renaming them.How can I help you explore Laravel packages today?