tourze/json-rpc-http-direct-call-bundle
Tourze's JSON-RPC HTTP Direct Call bundle lets Symfony apps invoke JSON-RPC services directly over HTTP with minimal boilerplate. Register endpoints and dispatch requests through a lightweight, framework-integrated client for simple, fast remote calls.
tourze/json-rpc-http-direct-call-bundle is a Symfony-style bundle that wraps JSON-RPC 2.0 over HTTP into a directly-callable client, so you write $client->call('method', $params) instead of hand-rolling payloads, headers, and envelope parsing. The 1.1.0 release only ships a compare link (1.0.1...1.1.0), so the first thing to do is read that diff before you commit to the upgrade.
Minimal steps:
composer require tourze/json-rpc-http-direct-call-bundle:^1.1 — then immediately diff the vendor tree against 1.0.1 (composer require tourze/json-rpc-http-direct-call-bundle:1.0.1 --dry-run, or just open the compare URL). With no written release notes, the diff is the changelog.composer.json (PHP + symfony/* constraints — this tells you how much of the framework it drags in), then at the class that implements the direct call. That class is your actual integration surface; everything else is Symfony DI glue you'll likely replace in Laravel.config/services.php.Bind once, inject everywhere. Register the client in a ServiceProvider as a singleton keyed by connection name. Avoid new Client() in controllers — the whole point of the bundle is that the transport/config is resolved for you.
$this->app->singleton('jsonrpc.billing', fn ($app) => new DirectCallClient(
endpoint: config('services.billing.rpc_url'),
headers: ['Authorization' => 'Bearer '.config('services.billing.token')],
timeout: 5,
));
Config-driven endpoints. Keep URL, token, timeout, and retry count in config/services.php under a jsonrpc key, and read them via config(). Do not let the bundle's own Symfony YAML config become a second source of truth — mirror it or bypass it.
Wrap it, don't call it raw. Put a small BillingRpcClient class around the bundle client with one typed method per remote procedure. This gives you a place to normalise errors, log, and swap the transport in tests. It also isolates you from constructor signature changes in a minor release — which, given the silent changelog, is a real risk.
Batch deliberately. If 1.1.0 supports batched calls, remember JSON-RPC batch responses are unordered: index the results by id before mapping, never by array position.
Push slow calls to the queue. A JSON-RPC call is a network round trip inside your request cycle. For anything non-blocking, dispatch a job and let the job hold the client. Set an explicit timeout on the job ($timeout) slightly above the client timeout so you get a useful failure rather than a killed worker.
Test with a fake transport. Symfony's MockHttpClient (or Laravel's Http::fake() if you're routing through the Laravel HTTP client underneath) lets you assert the exact JSON-RPC envelope — jsonrpc, method, params, id — and feed back canned success and error bodies. Bake one success fixture and one error fixture into your test suite early; they'll catch envelope regressions across upgrades.
Map to DTOs at the boundary. Hydrate the result payload into a typed object inside your wrapper. Downstream code should never see the ['jsonrpc' => '2.0', 'result' => ...] envelope.
error object. If you only check status codes, you will silently treat failures as empty successes. Always branch on isset($response['error']) before reading result.1.1.0 has no prose release notes. Treat it as an unknown-risk minor. Pin to ^1.1 only after reading the compare diff; if the diff touches constructor signatures, config keys, or the response-handling path, pin to 1.0.* and schedule the upgrade deliberately.php artisan vendor:publish guarantees, and any YAML config the bundle expects won't be loaded. Expect to instantiate the underlying client yourself and use the bundle mainly for its transport/envelope logic.php artisan config:cache. Resolve values in the service provider's register(), not lazily per request.id) get no response body. If you drop the id for fire-and-forget calls, don't try to parse a result — the client may legitimately return null or an empty body.(string) $sent === (string) $received) when matching batch results.params over blind retry.How can I help you explore Laravel packages today?