Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Error Bundle Laravel Package

jenky/api-error-bundle

A PHP bundle for standardizing API error responses, helping you return consistent JSON error payloads across endpoints with minimal setup and configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Confirm the target framework first. jenky/api-error-bundle is distributed as a Symfony bundle, not a Laravel package. There is no service provider, no config/api-error.php, and no facade. On a Laravel codebase your options are (a) port the concepts, or (b) use it in a Symfony service inside a monorepo/BFF layer. Check composer.json (type: symfony-bundle, require: symfony/http-kernel) before assuming composer require jenky/api-error-bundle gives you anything in config/app.php.
  • Where to look first: the bundle class (Jenky\ApiErrorBundle\ApiErrorBundle), any DependencyInjection/Configuration.php (the only real source of truth for options), and the exception-mapping/listener classes. The README is thin; the config tree and the tests are the documentation.
  • Minimal wiring in a Symfony app:
    // config/bundles.php
    return [ Jenky\ApiErrorBundle\ApiErrorBundle::class => ['all' => true] ];
    
    Then bin/console config:dump-reference api_error (or whatever the extension alias is) to see the available knobs — do this before writing any code, because most "why is my error shape wrong" questions are answered there.
  • First use case: make a JSON API stop leaking HTML error pages and stack traces. Throw a domain exception from a controller, and let the bundle translate it into a stable JSON/RFC 7807-style payload with a correct HTTP status. Verify by curling a deliberately failing route with Accept: application/json and inspecting both the body and the Content-Type header.
  • Pin the version. You are on 0.3.x — pre-1.0. Use a caret constraint with an explicit floor ("jenky/api-error-bundle": "^0.3.1") and commit the lockfile; do not float on * or dev-master.

Implementation Patterns

  • Exception → status mapping as configuration, not if chains. Define a map of exception class → HTTP status + machine-readable error code, and keep controllers free of try/catch blocks that only re-shape the payload. This is the main day-to-day win: controllers throw domain exceptions, the bundle renders them.
  • Domain exceptions carry intent. Create a small hierarchy (NotFoundException, ValidationFailedException, ConflictException) extending a base ApiException that carries a status code and an error code. Map the base class once; subclasses inherit. This scales far better than listing every concrete class in config.
  • Normalization layer. Let the bundle own the envelope (type, title, status, detail, code, plus a meta/errors bag) and have your exceptions supply only the variable parts. Consumers then get one shape for every failure, which is what makes client-side error handling possible.
  • Validation errors are the exception (pun intended). Framework validation exceptions usually carry a ConstraintViolationList-style structure. Write a dedicated mapper/normalizer that flattens violations into errors: [{ field, message }] — otherwise you get a nested object graph that leaks framework internals into your public API.
  • Integration with content negotiation. Gate the JSON rendering on the request asking for it (Accept: application/json, */* from an XHR, or a route prefix like /api/*). Keep HTML error pages for browser traffic; a global override confuses users and breaks debug tooling.
  • Logging policy. Split "expected" from "unexpected": map 4xx exceptions at warning/info with no stack trace, and let 5xx bubble or log at error with the exception attached. Doing this in one place prevents the classic double-log problem after the listener renders the response.
  • Testing pattern. Write one feature/functional test per mapped exception asserting status + JSON shape via JSON assertions, not string matching on the body. Add a single test proving an unmapped exception returns the generic 500 envelope without a trace.
  • Laravel-shaped alternative if you stay on Laravel. Reproduce the same three pieces in bootstrap/app.php (Laravel 11+) with ->withExceptions(function (Exceptions $exceptions) { ... }) and a render() method on a base ApiException. You get the ergonomics without the bundle, and RFC 7807 payloads are easy to emit with response()->json($problem, $status, ['Content-Type' => 'application/problem+json']).

Gotchas and Tips

  • 0.3.1 has no human-readable changelog — the release notes are only a compare link. Read the diff for 0.3.0...0.3.1 before bumping: on a 0.x package, behavior fixes can alter payload keys or status codes without a major-version signal. Treat every patch as potentially significant and re-run your error-shape contract tests.
  • Pre-1.0 API instability is the headline risk. Class names, config keys, and extension points are all fair game between minors. Wrap the bundle behind your own ApiErrorFactory/normalizer service so a future rename costs you one adapter class, not fifty call sites.
  • Bundle config vs. framework config precedence. Symfony's framework.exceptions / the error controller can win over a listener depending on where the exception is thrown (kernel vs. controller, sub-requests, kernel.exception priority). If your mapper "sometimes" isn't called, check listener priority and whether the error is rendering through the error controller instead.
  • Debug mode changes the shape. APP_DEBUG=1 typically exposes class names, messages, and traces. Make sure your tests run with debug off at least once, and never let a detail field be populated from getMessage() of an unmapped exception in production — that's an information-disclosure bug waiting to happen.
  • Content-Type must be application/problem+json (if you're claiming RFC 7807) — not application/json. Some clients and API gateways branch on this header. Set it explicitly rather than inheriting the default.
  • Errors are not exceptions. \Error, \TypeError, and fatal errors bypass the exception listener in some paths. Don't assume a 500 from a fatal will be shaped like your envelope; add a fallback at the server/edge layer if the contract matters.
  • Double logging. Once the listener converts an exception into a response, the framework may not log it at all (good) or may log it twice (bad, if you also log in a mapper). Pick one owner for logging and document it.
  • Localization/title strings. Don't hardcode English copy inside mappers. Route through a translator or a message catalogue keyed by error code so title/detail can be localized later without touching mapping logic.
  • Extension point to lean on: custom mappers/normalizers registered by tag (or by config key) rather than subclassing the central handler. That's the seam most likely to survive upgrades — and in a Laravel port, it maps cleanly to a match (true) over exception types in a single render() method.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route