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

Jsonrpc Client Laravel Package

tochka-developers/jsonrpc-client

A PHP/Laravel JSON-RPC client for connecting to remote JSON-RPC services with a clean, expressive API. It simplifies request building, endpoint configuration, and error handling, making it easy to integrate JSON-RPC APIs into Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require tochka-developers/jsonrpc-client

The service provider and JsonRpcClient facade are auto-discovered on Laravel 5.5+. On older versions (or Lumen) add Tochka\JsonRpcClient\JsonRpcClientServiceProvider to config/app.php and register the facade alias manually.

Publish the config and read it end-to-end — this is the first place to look.

php artisan vendor:publish --provider="Tochka\JsonRpcClient\JsonRpcClientServiceProvider"

The published file is the real documentation for this package: it defines named connections (URL, headers/auth, timeout, and any transport-specific options). The shape is roughly:

return [
    'default' => env('JSONRPC_CONNECTION', 'main'),
    'connections' => [
        'main' => [
            'url'     => env('JSONRPC_URL'),
            'timeout' => 5,
            'headers' => ['Authorization' => 'Bearer '.env('JSONRPC_TOKEN')],
        ],
    ],
];

Treat the keys as authoritative — copy them from the actual published file rather than from examples online, since the package has a small user base and its config has drifted between tags.

First call

use Tochka\JsonRpcClient\Facades\JsonRpcClient;

$users = JsonRpcClient::connection('main')->call('user.list', ['limit' => 10]);

If connection() isn't the selector in your version, check the facade's docblock / __call implementation — sibling packages in the Tochka family use to(), withClient(), or a client() factory. Pick the one the facade proxies and wrap it immediately (see below) so the rest of your app never depends on the raw call style.

Standalone PHP (no Laravel): construct the client directly with the same connection array. This is worth knowing because it lets you unit-test the client without booting the framework.

First real use case: one remote service, one typed wrapper class, called from a controller. Do not sprinkle JsonRpcClient:: calls through controllers — the very first thing to build is the wrapper.

Implementation Patterns

Wrap every remote service in a typed class, bind it in the container.

interface UserService { public function find(int $id): User; }

class RemoteUserService implements UserService
{
    public function __construct(private JsonRpcClient $rpc) {}

    public function find(int $id): User
    {
        $data = $this->rpc->connection('main')->call('user.get', ['id' => $id]);
        return User::fromArray($data);
    }
}

Inject the interface everywhere and resolve it in a service provider. Facade calls inside business logic are the thing you'll regret when you need to swap the transport or stub it in tests.

Map errors once, at the boundary. JSON-RPC failures arrive in two flavours (transport/HTTP and RPC-level error object). Catch both in the wrapper and rethrow as a domain exception, so callers never branch on error.code:

try {
    return $this->rpc->connection('main')->call('user.get', ['id' => $id]);
} catch (TransportException $e) {
    throw new UserServiceUnavailable(previous: $e);
} catch (RpcException $e) {
    throw $e->getCode() === -32602 ? new InvalidUserQuery(previous: $e) : $e;
}

Multiple connections = multiple named endpoints. Keep config/jsonrpc-client.php static (env-driven) for fixed services, and build per-tenant connections at runtime when the URL/host varies per customer — usually by merging into the config repository before resolution, or by constructing a client instance directly. Do not mutate the singleton connection object at request time.

Queue the flaky stuff. Anything non-interactive (sync jobs, webhooks fan-out) should go through a job with $tries/backoff rather than a synchronous call in a controller. JSON-RPC gives no idempotency for free; make the remote method idempotent or add your own request key.

Fire-and-forget notifications. For JSON-RPC notifications (no id), you don't need the response — but be explicit about it, because a client that waits for a response will block until the timeout when the server returns 204.

Testing. If the client sits on Guzzle/Laravel HTTP, Http::fake() is the cleanest seam — fake a canned JSON-RPC envelope and assert on the wrapper's typed output. If it doesn't, bind a fake UserService interface (which is why the wrapper exists) and test the wrapper itself against a local stub server or a mocked client object.

Gotchas and Tips

  • [] vs {} for params. An empty PHP array serializes to [], but many servers require a JSON object for named parameters. If you get -32600 Invalid Request only when calling with no arguments, cast to (object) [] or send a positional list deliberately.
  • Named vs positional params. JSON-RPC 2.0 accepts both; a server that declares named params will reject a positional list. Match the server's params declaration exactly, and document it in the wrapper's signature — this is the single most common integration failure.
  • RPC errors usually come back with HTTP 200. Never rely on status codes for business errors; always inspect the error member of the decoded envelope. Conversely, a 200 with a malformed body must still be treated as a transport failure.
  • Timeouts. Set both connect and read timeouts. A hung endpoint with no timeout will pin a PHP-FPM worker, and with pm.max_children small, one slow RPC can take the whole site down.
  • php artisan config:cache. Env-driven connection arrays are frozen at cache time. Any runtime-built connections must not read env() directly, or they'll silently resolve to null in production.
  • Log the raw envelope. Add a middleware/log line capturing the request id, method, and the raw response body. When a remote team says "we got nothing", this is your only evidence — the exception message alone rarely carries the payload.
  • Pin the version. Eight stars and a single maintainer means the API can shift in minor releases. composer require "tochka-developers/jsonrpc-client:^X.Y" with an explicit constraint, and run the wrapper's contract tests on upgrade.
  • Extension points worth knowing: custom transport/HTTP client injection, connection-level headers (use these for tracing/correlation IDs rather than editing every call), and the config default key — override it per-command via a container binding if you need different defaults for queue workers vs. web requests.
  • Batch responses may arrive out of order or partially. If you use batching, key results by id rather than by array position, and treat missing ids as errors.
  • Debugging checklist: (1) log the outbound JSON, (2) replay it with curl against the endpoint, (3) if curl succeeds and the package fails, the difference is almost always headers (auth/Content-Type) or the params shape — not the client logic.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle