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 Rpc Laravel Package

teamones/json-rpc

A JSON-RPC implementation for Laravel and PHP, offering request handling, method dispatching, and structured error responses for building RPC-style APIs and services.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a thin transport layer: it wraps PHP's stream_socket_client() so a Laravel app can speak JSON-RPC 2.0 to a backend over a raw TCP socket rather than HTTP. Treat it as plumbing, not a framework — there is no published documentation worth reading, so the source is the spec.

Install and discover the wiring

composer require teamones/json-rpc

Then read, in this order:

  1. composer.json → extra.laravel.providers / aliases. If present, the service provider is auto-discovered. If absent, register it manually in bootstrap/providers.php (Laravel 11+) or config/app.php.
  2. The service provider → what it binds into the container (usually a singleton for the client plus a mergeConfigFrom call), and which publish tag it exposes.
  3. config/*.php in the package → the connection shape. Expect host, port, timeout, and possibly a protocol/scheme key.
  4. The client class → how it frames requests (see Gotchas; this is the part that bites).

Publish the config and set one connection

php artisan vendor:publish --provider="Teamones\JsonRpc\JsonRpcServiceProvider"
// config/json-rpc.php — shape is indicative; match the package's own keys
return [
    'default' => 'internal',
    'connections' => [
        'internal' => [
            'host'    => env('RPC_HOST', '127.0.0.1'),
            'port'    => env('RPC_PORT', 9000),
            'timeout' => 3.0,
        ],
    ],
];

First use case: an internal service call from a controller or job — {"jsonrpc":"2.0","method":"order.status","params":{"id":42},"id":1} out, {"result":{...}} back. Resolve the client from the container (facade if one is aliased), call the method, assert the response envelope before touching result.

Before writing production code, prove the socket path with nc -v $RPC_HOST $RPC_PORT or a two-line stream_socket_client script. Half the failures with this style of package are network/ACL, not PHP.

Implementation Patterns

Never call the client from a controller. Wrap it in a small service per upstream so the envelope handling lives in one place:

final class OrderGateway
{
    public function __construct(private JsonRpcClient $client) {}

    public function status(int $id): OrderStatus
    {
        $response = $this->client->call('order.status', ['id' => $id]);
        // unwrap the envelope once, here, not in every caller
        return OrderStatus::fromArray($response['result'] ?? throw new RpcException($response['error']['message'] ?? 'unknown'));
    }
}

Connection selection. Multi-connection configs almost always mean "different upstream services, different timeouts". Prefer a named connection bound per-service in your own provider over passing a connection string at every call site — it keeps the timeout decision next to the config:

$this->app->when(OrderGateway::class)
    ->needs(JsonRpcClient::class)
    ->give(fn ($app) => $app->make(JsonRpcClient::class)->connection('orders'));

Bind as a singleton — but only if the client is re-entrant. A per-request instance is the safe default; a singleton avoids reconnect cost across multiple calls in one job. Verify the client resets its request id and buffer between calls before you promote it.

Distinguish the two failure modes everywhere. Transport failure (socket refused, timeout, connection dropped mid-read) is an infrastructure problem — retry, circuit-break, page someone. A JSON-RPC error object with a valid id is a successful round trip carrying an application error — do not retry it, surface it to the user. Collapse these into one exception type and you will retry "insufficient balance" forever.

Idempotency for writes. Over raw TCP there is no request-level retry semantics like HTTP. If you retry a placeOrder after a read timeout, you may duplicate. Pass a client-generated idempotency key in params and have the server honour it, or restrict automatic retries to read methods.

Testing. Bind a fake in the container rather than hitting a socket in CI. If the package exposes a facade, Facade::swap() / shouldReceive works; otherwise bind an interface your gateway depends on and keep the package's client out of the test path entirely:

$this->mock(OrderGateway::class, fn ($m) => $m->shouldReceive('status')->andReturn(OrderStatus::paid()));

Queue the chatty parts. Each call is a socket round trip; N sequential calls in a request is N× your RTT. If the server supports batch arrays (many JSON-RPC servers do), batch reads. Otherwise move multi-call workflows into a job.

Gotchas and Tips

  • TCP is a stream, not a message channel. fread() will happily return half a JSON document. If the package frames by newline (\n-delimited JSON), any payload containing a literal newline inside a string breaks framing unless it is JSON-escaped — it usually is, but confirm. If it frames by length prefix, confirm it loops until it has read the full declared length. This is the single most likely source of intermittent "json_decode failed" errors under load, and it never reproduces locally.
  • stream_socket_client timeout is a float in seconds, and the default default_socket_timeout (60s) will silently mask a missing config key. Set it explicitly; a hung RPC has no HTTP-level deadline behind it.
  • false return, not an exception. The underlying function returns false and emits a warning. Confirm the package converts that to an exception and doesn't leak a warning into your logs before your error handler sees it.
  • Retry storms. No connection pool and no keep-alive means a hot endpoint open/close per call. Combine a slow upstream with a queue of workers and you get Connection refused from the listen backlog. Add jitter to retries and cap concurrency.
  • Config cache. php artisan config:cache in deploy — connection changes require a re-cache. Classic "worked locally, wrong host in prod" cause.
  • Large integers. JSON-RPC ids and snowflake-ish ids exceed PHP's float precision if decoded loosely. Decode with JSON_BIGINT_AS_STRING where the package lets you, or expect id drift in responses.
  • Debugging. tcpdump -A -s0 -i any port 9000 or socat -v shows you the literal bytes on the wire — faster than any logging you add. Add a temporary Log::debug() of the raw request/response in a middleware-style decorator around the client, never inside vendor code.
  • Extension points are thin. Assume you can extend by (a) decorating the client through a container binding and (b) adding a connection entry. If you need custom framing, backoff, or auth handshakes, plan to fork or wrap rather than wait on upstream.
  • Maintenance risk is the headline. Zero stars, zero dependents, and a last release in the future relative to normal versioning hygiene — no community, no issue triage, no compatibility guarantees with PHP or Laravel majors. Before adopting, vendor the package (composer require then commit to a private VCS repo, or copy the ~few hundred lines into app/Support). At this size, forking is cheaper than being blocked by it, and it removes the upgrade risk entirely.
  • Auth and TLS. stream_socket_client supports ssl:// and tls:// transports with context options, but a package this small likely hardcodes tcp://. If you need transport security, check whether you can pass the scheme and stream_context options — if not, that's a fork-level change, and a reason to not adopt if the socket crosses an untrusted network.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package