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

Json Api Symfony Laravel Package

haddowg/json-api-symfony

A Symfony bundle for building JSON:API-compliant APIs, handling resource serialization, relationships, and spec-compliant responses with minimal configuration.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Confirmed at v1.0.0: the package is a Symfony bundle built around Doctrine ORM (DataProviderInterface, DoctrineExtensionInterface, ExtensionContext). There is still no Laravel service provider, Eloquent data provider, or Laravel validation bridge. Treat "Laravel support" as an integration project we own, not a configuration flag.
  • The architecture is sound and deliberately layered: a data-layer SPI (base classes + provider interface, plus an advertised id pattern in OpenAPI), composable per-type capabilities, an OpenAPI metadata layer, an exception-to-error mapping seam, and extensions (Atomic Operations, relationship queries, counts, custom actions, async writes). This is a spec-faithful JSON:API implementation, not a thin serializer.
  • The SPI is the real integration contract and it moved in 1.0.0: DataProviderInterface now mandates relatedToOneMatches() and relatedToOneMatchesBatch(), and DoctrineExtensionInterface::apply() takes an ExtensionContext instead of loose arguments. There is also a new typed constraint-translator extension with the Custom bridge dropped — an Eloquent filter bridge must be written against the typed contract, not the old one.
  • A new custom-encoded / policy-sourced resource id capability makes id generation a policy decision rather than a column read. For an Eloquent adapter this is helpful (we can map ids from a policy instead of forcing a DB column shape) but it is another seam to implement.

Integration feasibility

  • Feasible for a PHP 8 team comfortable with the JSON:API spec. Blocking unknowns remain the Laravel-side seams: authorization (Symfony security expressions vs Laravel gates/policies), validation (Symfony Validator bridge vs Laravel's validator), and persistence (Doctrine vs Eloquent).
  • The 1.0.0 feature set is now real, not projected: consolidated query engine, cursor/keyset pagination on collections, related collections and linkage endpoints, pivot filter operators, constrained existence, custom (non-CRUD) actions, Atomic Operations extension, async write seam (202/303), cache and deprecation headers, strict query parameters, write-only attributes, readOnly resource shorthand, composite attributes, and OpenAPI bridging of descriptions, security booleans, and the id pattern.
  • The build-time failure gating (polymorphic, Doctrine-column, pivot, routed-but-unservable types, sortable projection) is a genuine quality signal: misconfiguration is caught in CI, not in production. Note it is Doctrine-shaped gating — an Eloquent adapter inherits none of it for free.
  • readOnly shorthand materially lowers the cost of our read-only pilot: one decorator instead of hand-disabling write capabilities.

Technical risk

  • Ecosystem mismatch remains the top risk. Every breaking change in 1.0.0 is Symfony/Doctrine-shaped and none of the release evidence shows a Laravel test matrix. We are adopting a package whose maintainers do not test our stack.
  • 1.0.0 landed ~25 breaking changes in a single release, exactly as the pre-release assessment anticipated. The surface moved from on() attributes to flattened attributes, linkage methods renamed to data, lazy-by-default linkage, opt-in counting, pagination as single source of truth, removed zero-config pivot filter (filter[position]), and a removed Custom constraint bridge. 1.0.0 is a stabilisation event, not evidence the churn is over.
  • Single-maintainer concentration (all issues/commits trace to one GitHub account). No foundation, corporate sponsor, or LTS policy.
  • Security semantics changed materially and shipped: a resource's read-security expression now also gates GET /{type}/{id}/{rel} and /relationships/{rel}, relationships can be authorized independently of the parent, and collection reads require a securityList key. Correct behaviour, but it will surface as new 403s in any consumer built against pre-1.0 behaviour.
  • Absolute links by default (request-host-absolute) is a reverse-proxy/trusted-host configuration dependency that will bite in containerised deployments.
  • Custom-encoded ids change the id strings clients cache and route on. If we adopt id policies, that is a client-facing contract decision, not an internal one.

Key questions

  1. Is there a supported Laravel/Eloquent path, or is the SPI the only seam? Who owns the adapter?
  2. Minimum PHP and Symfony versions, and is there any Laravel version matrix at all?
  3. What is the BC policy now that 1.0.0 has shipped — semver-strict, or "breaking changes in minors"?
  4. Which JSON:API spec version/profile set is the compliance target (relationship queries, counts, atomic operations, composite attributes)?
  5. How do security expressions map onto Laravel gates/policies — is a bridge planned or must we write it? Same question for the Validator bridge and the new typed constraint translator.
  6. Is the OpenAPI output — now including descriptions, security booleans, and the id pattern — consumed by our contract-testing and SDK-generation pipeline?
  7. Do we want policy-sourced/custom-encoded ids, and if so when, given the client-visible contract impact?
  8. Maintainer capacity: release cadence post-1.0.0, issue triage SLA, security disclosure process?

Integration Approach

Stack fit

  • Clean fit if the target service is Symfony + Doctrine. Marginal fit for Laravel: we implement an Eloquent DataProviderInterface (including both batch match methods), a typed constraint-translator for our filter vocabulary, an authorization predicate adapter over gates/policies, and a validation adapter — then maintain all four.
  • Best-fit use case is a bounded, read-heavy, spec-conformant API surface — public or partner-facing collections with filtering, sorting, sparse fieldsets, includes, and cursor pagination — rather than a whole-application API layer.

Migration path

  • Do not retrofit an existing REST surface wholesale. Stand up a new JSON:API resource type behind the same domain services and route traffic per-endpoint.
  • Pin 1.0.0 exactly in composer.json with a committed lockfile; treat every subsequent release as a code change requiring review and a full test run.
  • Sequence the SPI adapter first and prove it against a single low-risk resource before any write paths.

Compatibility

  • Verify PHP version, PSR/Symfony component constraints, and whether any transitive dependency conflicts with the Laravel framework version in use.
  • Because Custom constraint bridging was removed, any filter-mapping code we prototype must target the typed translator; do not build on pre-1.0 examples found in blog posts or older docs.
  • Confirm OpenAPI 3.x output shape against our contract tests; description overrides, security booleans, and the id pattern mean doc drift is now a build concern.
  • Check that strict query-parameter and strict sparse-fieldset gates produce error documents our clients can parse (the exception-to-error mapping seam is the hook).

Sequencing

  1. Spike (1–2 weeks): one read-only resource declared with the readOnly shorthand, Eloquent provider prototype, OpenAPI export, measure adapter effort honestly.
  2. Adapter hardening: batch relationship matching, typed constraint translator, authz predicates, validation bridge; contract tests against the JSON:API spec.
  3. Pilot resource in production behind a feature flag; read paths only, with securityList and read-security expressions wired to Laravel gates.
  4. Write paths: create/update, then relationship endpoints, then pivot writes via meta.pivot.
  5. Advanced surface, only if demanded: Atomic Operations, custom actions, async write seam (202/303), cursor pagination rollout, policy-sourced ids.
  6. Observability and caching: cache/deprecation headers, link-host configuration validated behind the load balancer.

Operational Impact

Maintenance

  • Budget a standing upgrade allocation. 1.0.0 confirmed ~25 breaking changes at once; do not assume the churn ends here. Treat the next two minors as scheduled work, not contingency.
  • We own any Laravel adapter code permanently — provider, constraint translator, authz and validation bridges. That is an ongoing internal maintenance line item with no upstream backing.
  • Build-time configuration validation is a maintenance credit: it converts silent runtime misbehaviour into CI failures. Budget for it firing on release day.

Support

  • No commercial support, no vendor SLA, single-maintainer project. Acceptable for internal or low-blast-radius APIs; a governance concern for anything revenue-critical or contractually spec-bound.
  • Mitigation: fork-and-vendor rights, a named internal owner, and a documented exit path (the SPI means we could swap the engine without rewriting domain code).

Scaling

  • Positives: consolidated query engine, opt-in counting and pagination-as-single-source-of-truth, cursor/keyset pagination on collections, related collections and linkage endpoints, and constrained existence — all reduce the classic JSON:API N+1 and COUNT(*) blowups.
  • Watch: lazy-by-default relationship linkage shifts cost to include-time; verify query plans under realistic include depth.
  • Pivot-filter operators and relationship-queries profiles can generate heavy joins; load-test the real filter combinations, not the happy path.

Failure modes

  • 403 regressions from the shipped relationship/related-endpoint security gating, independent relationship authorization, and the securityList key on collection reads — the most likely production surprise.
  • 400s from strict query parameters and strict sparse-fieldset rejection where clients previously sent junk silently; plus the removed filter[position] pivot filter, which will now fail as an unknown parameter.
  • Wrong-host links in API responses when absolute-link generation runs behind a proxy without trusted-host configuration.
  • Build breaks from the misconfiguration gates (polymorphic, Doctrine-column, pivot, unservable routed types, sortable projection) — good failure, but it lands on upgrade day.
  • Async write semantics (202 + 303) require client-side polling/redirect handling; only adopt with a client that supports it.
  • SPI signature drift breaking custom providers at compile time when the interface gains methods — pin versions and run the full suite on every bump.
  • Id contract drift if we adopt custom-encoded or policy-sourced ids without versioning the id string format for clients.

Ramp-up

  • Steep. Engineers need JSON:API fluency (sparse fieldsets, includes, linkage vs related endpoints, error documents) plus the package's own vocabulary: capability composition, profiles, flattened attributes, meta.pivot, securityList, extension contexts, and the typed constraint translator.
  • Recommended: a half-day spec primer, the example app as the reference implementation (it now showcases composite attributes and the full extension surface), and one engineer designated as the package owner before the pilot begins. Do not start the spike and the adapter work in parallel with different owners.
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