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 Exception Bundle Laravel Package

soft-passio/api-exception-bundle

A PHP bundle for standardized API exception handling, converting errors into consistent JSON responses with configurable status codes and payloads. Helps keep API error output predictable and easy to debug across services.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a scoping note: despite the prompt framing, this is a Symfony bundle, not a Laravel package. There is no service provider or config/app.php entry. If you are a Laravel developer, treat it as a reference implementation to port (Laravel's analogue is an App\Exceptions\Handler::render() override or a global middleware that maps exceptions to an application/problem+json body) rather than something you composer require into a Laravel app.

Minimal steps for a Symfony app:

  1. Install: composer require soft-passio/api-exception-bundle. The package has no tagged release after 2020-06-17, so pin explicitly and check the composer.json symfony/* constraints against your Symfony version before committing. Expect Symfony 4.4/5.x-era code; Symfony 6/7 will likely need a fork or extra.symfony.require conflict resolution.
  2. Register the bundle in config/bundles.php (typical entry: SoftPassio\ApiExceptionBundle\ApiExceptionBundle::class => ['all' => true] — confirm the exact FQCN from the repo's src/ directory, as namespaces in small bundles are easy to misremember).
  3. Look first at the event subscriber / listener the bundle ships (search for kernel.exception or KernelEvents::EXCEPTION). That class is the whole package: it is the thing deciding which exceptions become Problem JSON and which pass through. Everything else is config and DTOs.
  4. Confirm the response shape with a smoke test: hit a route that throws, and assert Content-Type: application/problem+json and a body containing type, title, status, detail, instance.

First real use case: a JSON API where every error — validation failures, 404s, uncaught \Throwable — must return a consistent RFC 7807 document instead of Symfony's HTML error page or an inconsistent {"error": "..."} shape. The bundle's value is exactly one thing: centralising that conversion so controllers never build error responses by hand.

Implementation Patterns

Treat it as a translation layer, not a response builder. The bundle sits on kernel.exception and converts an exception into a ProblemDetails-style payload. In your controllers and services you keep throwing ordinary domain exceptions; the listener maps them. Don't call into the bundle directly from business code.

Map your domain exceptions to status codes. The core day-to-day pattern is: define small exception classes (ValidationException, NotFoundException, ConflictException) and teach the library's mapping (config or an instanceof check in a decorator) which HTTP status and type URI each produces. Keep the mapping declarative and in one place — a config/packages/api_exception.yaml block or a single map array — so an auditor can read the whole error contract in thirty seconds.

Use detail vs type deliberately. type is a stable URI identifying the class of problem (documented, linkable); detail is the occurrence-specific human string. A common failure is stuffing a stack trace or SQL fragment into detail — that leaks internals and is the single most common security review finding for these layers.

Preserve framework exceptions where RFC 7807 already fits. Symfony's HttpExceptionInterface already carries a status code and headers. Your listener should defer to it (and propagate its headers, notably WWW-Authenticate for 401 and Allow for 405) rather than flattening everything to 400/500. If the bundle doesn't do this, wrap its subscriber or add a higher-priority listener.

Validation integration. If you use the Symfony Validator, catch ValidationFailedException and emit a Problem document with an errors extension member array (field → messages). RFC 7807 explicitly permits extension members; this is where the spec pays off versus bespoke error envelopes. Consumers can parse per-field errors without guessing the shape.

Logging split. Let the listener emit at warning for 4xx (client error, usually not actionable as an incident) and error/critical with the exception for 5xx. If the bundle swallows exceptions silently, add a listener with higher priority that logs before the conversion, or decorator-wrap the converter.

Testing seam. Assert on the problem body, not the exception. A functional test per mapped exception ($client->request(...); $this->assertResponseHeaderSame('Content-Type', 'application/problem+json') plus a JSON assertion on status and type) gives you a regression suite that survives swapping this bundle out for a hand-rolled listener.

Migration tip for Laravel devs: the equivalent implementation is a JsonExceptionRenderer invoked from Handler::render(), plus a prepareException() map from exception → status. Lift the bundle's mapping table and problem-document DTOs; discard the Symfony plumbing.

Gotchas and Tips

  • Unmaintained since June 2020. Zero stars, zero dependents, no release in ~4 years. This is a "read the source and copy the idea" package, not a dependency to build a product on. Budget for a fork (vendor it under your own namespace) or replacement with Symfony's built-in framework.exceptions config + ErrorListener (Symfony 5.1+ ships RFC 7807-shaped problem responses natively via the serializer's ProblemNormalizer). That built-in path is what you should compare against before adopting this.
  • Symfony version drift is the practical blocker. 2020-era bundles commonly reference Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent (removed in Symfony 5) rather than ExceptionEvent. If the bundle declares Symfony <5.0, installation into a modern app fails outright. Check composer.json require before anything else.
  • Debug mode changes behaviour. In dev, Symfony's DebugHandlersListener/ErrorHandler may render its own trace page with higher priority, so "it works in prod only" is normal. Verify in prod or set kernel.debug: false in the test environment; don't chase a bug that is just the profiler winning the listener race.
  • Priority ordering. The exception event runs listeners by priority. A listener from another bundle (API Platform, Sentry, FOSRest) registering at a higher priority can preempt this one, leaving you with mixed error formats. Inspect debug:event-dispatcher kernel.exception and set priority explicitly.
  • instance is often wrong or absent. Many small bundles omit instance or set it to a fixed string. Per RFC 7807 it should identify the specific occurrence (typically the request path or a correlation ID). Add it in a decorator so your 500s can be correlated with logs.
  • Content negotiation. Returning application/problem+json for a request whose Accept: text/html is arguably wrong; if you have browser-facing routes on the same app, scope the listener to /api/* or Accept-based matching, otherwise error pages become raw JSON in the browser.
  • type: about:blank is valid — and often correct. Per RFC 7807, the default type is about:blank and title should then be the HTTP status phrase. Don't invent a type URI per exception unless you actually host documentation at that URI; dangling type links are worse than the default.
  • Extension points to know before forking: the exception→problem mapping, the content-type constant, and the detail renderer. Those three are where all real customisation happens; everything else is boilerplate. Fork only if you need to add error extensions (trace IDs, validation arrays) — otherwise a 40-line listener gets you 95% of this package's behaviour with no maintenance debt.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager