mnavarrocarter/problem-details-bundle
A Symfony bundle for RFC 7807 problem details that turns exceptions and validation errors into consistent application/problem+json API responses with configurable type, title, status, detail, and custom extension fields. Ideal for standardizing HTTP API error handling.
Architecture fit — still a mismatch; the new release confirms it. The 0.1.0 notes describe an exception listener plus serializers for "Doctrine, HttpFoundation and Symfony Security" exceptions. That is a Symfony kernel.exception event subscriber wired through container-tagged auto-registration, plus a serialization matrix keyed on Symfony's exception classes. Laravel has no equivalent machinery: it has a single App\Exceptions\Handler, a render/report split, and no bundle auto-discovery or tag-based subscriber registration. Nothing in 0.1.0 introduces Laravel support, a service provider, or a framework-agnostic core. The parts that save time — the listener auto-registration and the pre-built Symfony exception map — are exactly the parts that do not port.
The genuinely useful new content is narrower than the headline suggests: the package now documents which exceptions matter and how to shape them. That is a design input, not an integration path. It also introduces Doctrine and Symfony Security exception types that have no direct Laravel analogue, so the mapping table needs re-derivation against Laravel's exception set (ValidationException, AuthenticationException, AuthorizationException, ModelNotFoundException, ThrottleRequestsException, TokenMismatchException) rather than translation.
Integration feasibility — unchanged: feasible as an extraction, not an adoption. The realistic path remains reading the source, lifting the payload-shaping logic, and reimplementing it in Laravel's handler or a custom renderer. Still roughly 1–3 engineer-days including contract tests. Installing the package in a Laravel app still requires Symfony framework-bundle semantics Laravel does not provide.
Technical risk — revised, and the shape of the risk has changed materially:
| Risk | Severity | Notes |
|---|---|---|
| API instability / pre-1.0 churn | High | 0.1.0 is by definition an unstable, unproven API. Semver-major is not reachable without breaking changes; expect the serialization surface and listener contract to move. |
| Dependency conflict | High | Release notes give no constraint update. The package still orbits Symfony components; Laravel 10/11 ship Symfony 6/7. Resolution must be re-verified — the version bump is not evidence of modernisation. |
| Standards drift | Low–Medium | No mention of RFC 9457 in the release notes. Assume RFC 7807 (2016) semantics until shown otherwise. Structurally near-identical; wording and type URI guidance only. |
| Abandonment | Low–Medium (was High) | Superseded by the 0.1.0 release. Downgraded, not cleared: a single release after dormancy plus an "Initial Release" label at 0.1.0 is a restart, not a cadence. No evidence of CI, release process, or triage yet. |
| Zero validation | Medium | Release notes still indicate no visible dependents or field usage. A 0.1.0 initial release has, by construction, no production track record. |
| PHP version drift | Medium | Unvalidated against PHP 8.x until the composer.json constraints are read. Do not infer from the release. |
| Supply chain | Medium | One release does not constitute a security response path. No CVE process stated. |
| Provenance ambiguity | Medium | Prior metadata indicated a 2018-04-04 release; 0.1.0 is labelled "Initial Release." That is either a re-scoped rewrite, a re-tag, or a different lineage than what was assessed. Resolve before scoring anything else. |
Key questions to answer before any commitment:
composer.json now constrain for PHP and Symfony components? Five minutes, decides installability.HttpFoundation request/response types?Accept: application/problem+json, or will the shape change go unread?Stack fit — still none for the package; the idea remains sound. RFC 7807/9457 is a format, and formats are cheap. Laravel already supplies Handler::render, Responsable, withHeaders, and content negotiation via $request->accepts(). The listener model is the one piece Laravel cannot host, and it is the piece the release leads with.
Options assessed:
| Option | Viability | Effort | Verdict |
|---|---|---|---|
| A. Install package as-is in Laravel | Not viable | High + fragile | Reject — 0.1.0 adds serializers, not portability |
| B. Fork and maintain it | Viable but pointless | Medium ongoing | Reject — maintaining a Symfony bundle for a Laravel app is all cost |
| C. Extract the serialization design, reimplement in Laravel handler | Viable | 1–3 days | Recommend — slightly better input than before, same code |
| D. Adopt a maintained Laravel-native equivalent | Viable if one exists | 1–2 days | Evaluate first — no change to preference |
What 0.1.0 changes about Option C. The release is now a better reference document and no better a dependency. The serialization matrix for Doctrine, HttpFoundation, and Symfony Security exceptions is a useful checklist of "which exception families deserve dedicated problem documents and status codes." We map that intent onto Laravel's exception set and discard the class references. Net effect: marginal upside to the extraction option, zero effect on A or B.
Migration path (Option C, essentially unchanged):
type URIs (https://api.example.com/problems/validation-failed), canonical title strings, allowed extension members. Use 0.1.0's serializer list as a prompt for coverage, not as a spec.{type, title, status, detail, instance} plus extension members.App\Exceptions\Handler::render ahead of Laravel's default JSON path, with explicit branches for ValidationException (422 + errors), AuthenticationException (401), AuthorizationException (403), ModelNotFoundException (404), ThrottleRequestsException (429), and a catch-all 500 that never leaks internal messages into detail.Content-Type: application/problem+json, honour Accept negotiation, fall back to plain JSON for clients that don't ask.Compatibility concerns to sequence deliberately:
dontReport, and observability packages (Sentry, Ignition, Telescope) may intercept first. Pin precedence explicitly.Maintenance — we own it either way. The 0.1.0 release changes the reason but not the conclusion: adopting a pre-1.0, single-maintainer, Symfony-only package at version 0.1.0 means signing up for breaking changes with no reciprocal support commitment. Extraction still inverts this favourably — ~100–150 lines we control, covered by our own tests, no third-party upgrade treadmill, and we own the RFC 9457 migration as a documentation change.
Support — improved but unproven. There is now an active maintainer signal, which is a genuine improvement over the previous read. It is not a support contract: no stated deprecation policy, no release cadence, no visible issue triage, no security process. Under semver, 0.1.0 explicitly reserves the right to break on any minor. Budget on the assumption that bugs are ours.
Scaling — negligible. Error-path-only code. No throughput, memory, or pool concerns. The one scaling-adjacent risk is log volume if detail is verbose — keep it terse, push diagnostics to structured logs with a correlation ID echoed into the payload.
Failure modes to design against explicitly:
detail. Generic detail on 5xx; verbose detail gated by environment.type URIs. Treat as versioned, tested artifacts; dead links degrade the standard's value.null fields, not errors. Negotiation-gated rollout plus a deprecation window.Ramp-up — low, and still an argument for building it. RFC 7807/9457 is small and well documented; a mid-level Laravel engineer implements and tests it in a couple of days and then understands it completely. Adopting the bundle teaches Symfony DI internals the team cannot use in a Laravel codebase, and 0.1.0's serialization matrix is the only part worth reading closely.
Bottom line for the decision record (revised): the 0.1.0 release lowers the abandonment concern and raises the volatility concern; the net recommendation is unchanged. Do not adopt this package. Treat it as a reference implementation — now a slightly richer one, with a useful exception coverage checklist — worth 1–3 days of our own work. Two things must be resolved before this is re-scored: the provenance contradiction between the prior 2018 release and a 0.1.0 "Initial Release," and the actual PHP/Symfony constraints in composer.json. Absent those, the package remains a pre-1.0 Symfony-only artifact with no Laravel surface — and the functionality it provides is still small enough that reimplementing it is strictly cheaper than carrying it.
How can I help you explore Laravel packages today?