nanofelis/json-rpc-bundle
Symfony bundle for building JSON-RPC 2.0 APIs. Expose services as RPC methods, handle requests and errors consistently, and integrate JSON-RPC endpoints with Symfony routing and dependency injection.
Architecture fit — unchanged: poor as a direct dependency. 6.0.0 is still a Symfony bundle (NanofelisJsonRpcBundle). The integration surface remains the Bundle system — DI Extension, compiler passes, tagged services, service locators built at container-compile time, and Symfony routing/HttpKernel hooks. Laravel has no equivalent for the pieces this release leans into hardest. In fact 6.0.0 moves further into Symfony-specific machinery, not away from it.
Integration feasibility — still extraction-only, and the extractable core is now a smaller fraction of the package. The changes that make 6.0.0 good news for Symfony users are, almost without exception, wiring-layer changes that have no Laravel analogue and therefore no portability value:
#[JsonRpcService] key detection at container build time.#[MapRequestPayload] and custom argument resolvers work.kernel.controller_arguments replacing the removed RpcBeforeMethodEvent / nanofelis_json_rpc.before_method listener.#[JsonRpcService] autoconfiguration.None of that transfers. What does remain portable is the JSON-RPC 2.0 semantics core — parsing, dispatch, batch assembly, error-code mapping — and this release is a strong signal that the semantics core is now materially better than it was at 5.x. The 1–2 day spike should be scoped accordingly: find the parser/dispatcher/error-mapper classes, confirm they don't type-hint HttpKernel or resolve handlers through the Symfony container, and ignore everything above them.
Technical risk — meaningfully changed, in two directions.
Improved:
__construct on #[JsonRpcService] services, letting a caller re-invoke the constructor on the container-shared instance and overwrite injected dependencies for the remainder of the request — or the worker process under FrankenPHP/RoadRunner. That is a serious bug class, and the fix (an allowlist of public, non-magic, non-abstract methods; everything else answers -32601) is the correct one.[] now answers -32600; non-conforming id (float, array) answers -32600 instead of a TypeError/500; a missing jsonrpc key no longer emits an undefined-key warning en route to -32600.max_batch_size (default 100, 0 disables) addresses the batch-amplification hazard directly, which is the single hardest operational problem with this protocol shape.Worsened or newly introduced:
symfony/twig-bundle and ext-dom from transitive requirements — the latter is a silent breakage for anyone who was relying on them arriving for free. Irrelevant for a Laravel port, relevant if any adjacent tooling assumed them.Key questions for the requester/team:
Stack fit — unchanged: mismatch at the wiring layer. The realistic target remains Laravel-native code: a service provider for handler bindings, a route, and middleware for auth/throttling/logging.
Migration path — preference order unchanged, but the rationale for option 1 strengthens.
id validation, and method-surface allowlisting. Lowest long-term risk, full control of error semantics. Still the recommendation.id validation ourselves.Two things to lift from this release into our own build regardless of option:
-32601. Do not expose constructors, __destruct, __call, or inherited framework methods. This is now a known bug class in this protocol's PHP implementations, not a theoretical one.max_batch_size with a documented default. Adopt 100 (or lower) as a starting cap and make it configurable.Compatibility checks required before committing:
composer why-not nanofelis/json-rpc-bundle against the target Laravel version — Symfony 6.4/7/8 range is broader than before, but Laravel's pinned symfony/* versions still govern.symfony/twig-bundle or ext-dom arriving transitively — now explicitly removed.symfony/serializer or symfony/validator are pulled in; either expands the integration surface.Sequencing.
id. Preserving input order is strictly safer for interoperability; do that unless a client requires otherwise, and document the guarantee either way.id.id, missing jsonrpc key, method-not-found via disallowed surface. These are now known-tricky cases with known-correct answers.Maintenance. The ownership picture is unchanged in kind but improved in degree: the upstream project is demonstrably alive, ships migration documentation, and responds to security issues. That does not change the core fact — adopting it means owning a Symfony bundle inside a Laravel app — but it does make it a safer reference and a slightly less alarming thing to vendor from. Budget remains a small recurring allocation for spec conformance review on each new client onboarding. Note that 6.0.0 is a breaking release with a stated migration path; if we ever did vendor, we would now be tracking a moving target rather than a dead one, which is arguably better but is still work.
Support. No vendor, no SLA, no community of dependents. Escalation is "read the source." Unchanged. The security fix demonstrates the maintainer will act, but on no committed timeline, and we would have no advance notice of the next one.
Scaling. The batch-amplification hazard is now acknowledged upstream via max_batch_size — good validation that our concern was real, but the setting lives in bundle config and does not come with the core if we port it. We must implement the cap ourselves. Enforce a maximum batch size, apply rate limiting and authorization per method call rather than per HTTP request, and cap total batch execution time. Also confirm the response pipeline and any gateway in front of it handle a notification-only batch returning 204/empty correctly.
Failure modes to design for (updated).
-32601 for everything else.id.[] → -32600, not an empty array.id (float, array, object) → -32600, not a type error and not a 500.Ramp-up. The protocol surface is still small and a PHP developer is productive in a day. Two additions: the 8.4 floor may mean the reference implementation cannot be run locally during the spike, so allow extra time for reading rather than experimenting; and the absence of a maintained library still means the on-call engineer debugging a malformed batch reads our code, not upstream docs. That is acceptable if chosen deliberately and documented — the new changelog makes that deliberate choice easier to justify, because it hands us a curated list of the mistakes to avoid.
Overall recommendation — unchanged. Do not adopt nanofelis/json-rpc-bundle as a dependency in a Laravel codebase; it remains a Symfony bundle with no supported Laravel path. 6.0.0 does not alter that conclusion, but it does change the value of the package to us: treat it as a higher-quality design and test-case reference than at 5.x, lift the callable-method allowlist and batch-size cap into our native implementation, and mine the changelog for the spec edge cases it fixed. Revisit adoption only if the team standardizes on Symfony.
How can I help you explore Laravel packages today?