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.
code/message/data), param-by-position vs. param-by-name, and — as this release demonstrates — which methods are actually callable. This package is an existing implementation of that dispatch layer, so the decision remains "do we write, harden, and test ~200–400 lines of dispatcher + error mapping + an invocation allowlist, or adopt a dependency?"v2.pricing.quote) without REST URL churn — relevant for slow-moving enterprise partners.max_batch_size (default 100, 0 disables). This is the kind of knob PMs should care about — it converts "unbounded batch" from an infrastructure surprise into a product decision about how much work one HTTP call may trigger.id. If we ever ship a batch-capable API, that is a line item in our partner docs and SDK, not an implementation detail.Consider it when:
NanofelisJsonRpcBundle, a Symfony bundle. It is not a Laravel package, and 6.0.0 raises the floor further (PHP 8.4, Symfony 5 dropped) — the Laravel bridge idea is now more expensive, not less, since it would need to sit on a modern PHP runtime and reimplement container-integrated dispatch.#[JsonRpcService] autoconfigured, and now fails at container build time on duplicate keys or a tagged service missing the attribute. That last part matters: misconfiguration surfaces in CI instead of as a 500 in production.Look elsewhere when:
#[MapRequestPayload] and custom argument resolvers now work — validation still isn't free.)data field invite information leakage and enumeration.For executives: This is a small, MIT-licensed protocol component that would let us standardize internal RPC calls (one endpoint, predictable errors, batched requests) instead of hand-rolling that layer. The cost is not the license — it's integration and ownership. It's a Symfony bundle on a PHP 8.4 / Symfony 6.4–8 baseline, so on our Laravel stack it ships with an adapter we'd write and maintain. It remains a single-maintainer, near-zero-adoption project, so budget it as internal code, not a vendor dependency. The 6.0.0 release is worth noting for two reasons: it fixes a real security hole (a caller could re-invoke a service's constructor on the shared instance and overwrite its dependencies for the rest of the request or worker process), and it adds guardrails PMs care about — a batch-size cap and build-time failure on misconfiguration. That's evidence the project is actively hardened, but also evidence that a protocol layer is easy to get subtly wrong.
For engineering: 6.0.0 is a breaking release. PHP >= 8.4, Symfony 6.4/7/8, Symfony 5 dropped, ext-dom and twig-bundle no longer pulled in transitively. Behavior changes to plan around: the callable surface is now an allowlist of public, non-magic, non-abstract methods (everything else answers -32601); a malformed batch entry yields its own response while valid siblings still execute (previously one bad entry produced a non-array error and dropped the batch); responses may arrive in any order, so clients must key on id; empty batch [] returns -32600; RpcBeforeMethodEvent and the before_method tag are gone — move to kernel.controller_arguments, which now receives a faithful duplicate of the incoming request (headers, cookies, session, client IP) and is no longer flagged as a sub-request. Performance also changed: only the named service is instantiated, resolved via a compiler-pass-built service locator, instead of constructing every tagged service and its dependency graph per request.
If we're on Symfony, this is a straightforward adoption and worth roughly a one-week spike against our real method surface (batch, notifications, error mapping, kernel.controller_arguments listener for auth, max_batch_size tuning). If we're on Laravel, recommend not adopting the bundle directly — use it as a reference implementation and write a thin dispatcher bound into our service container. Either way we own auth, validation, rate limiting, and observability. And if we do hand-roll: copy the allowlist rule deliberately. The constructor-exposure bug is exactly the class of mistake a from-scratch dispatcher makes.
Recommendation: Low priority as a runtime dependency; materially better reference implementation than before. Do not adopt the bundle on a Laravel codebase. Revisit only if (a) the stack includes Symfony 6.4+/PHP 8.4 services, or (b) a partner contract mandates JSON-RPC 2.0 — in which case a one-week spike plus a vendored dispatcher is the low-risk path, with 6.0.0 as the spec and security reference. Anyone still on 5.x and actually running this should treat 6.0.0 as a required upgrade given the constructor-invocation fix.
How can I help you explore Laravel packages today?