PHPackages                             alcedo/json-rpc-server - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. alcedo/json-rpc-server

ActiveLibrary[API Development](/categories/api)

alcedo/json-rpc-server
======================

JSON-RPC server for executing functions remotely.

v1.3.2(6mo ago)045MITPHPPHP &gt;=8.2CI passing

Since Oct 28Pushed 6mo agoCompare

[ Source](https://github.com/Alcedo-Ltd/JSON-RPC-Server)[ Packagist](https://packagist.org/packages/alcedo/json-rpc-server)[ RSS](/packages/alcedo-json-rpc-server/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (6)Versions (10)Used By (0)

JSON-RPC Server
===============

[](#json-rpc-server)

A lightweight, PSR-friendly JSON-RPC 2.0 server for executing functions or objects remotely. It supports single and batch requests, notifications (no response), PSR-7 requests, and error handling compliant with the JSON-RPC 2.0 specification.

- PHP 8.2+
- PSR-7 `RequestInterface` support
- PSR Container for procedure lookups
- Strict DTOs for Requests/Responses/Errors
- Batch requests and notifications

Installation
------------

[](#installation)

Install via Composer:

```
composer require alcedo/json-rpc-server

```

Requirements:

- PHP &gt;= 8.2
- psr/http-message ^2.0
- psr/container ^2.0

Quick start
-----------

[](#quick-start)

### 1) Register procedures in a PSR Container

[](#1-register-procedures-in-a-psr-container)

Map method names to callables or to instances implementing `RemoteProcedureInterface`.

```
use Alcedo\JsonRpc\Server\Server;
use Alcedo\JsonRpc\Server\Factory\RequestFactory;
use Alcedo\JsonRpc\Server\RemoteProcedureInterface;
use Alcedo\JsonRpc\Server\DTO\Response;
use Psr\Container\ContainerInterface;

$map = [
    // Callable procedure: parameters will be passed from the JSON-RPC params array
    'sum' => function (int $a, int $b): int { return $a + $b; },

    // Object procedure: implement RemoteProcedureInterface
    'remote.ok' => new class implements RemoteProcedureInterface {
        public function call(): Response { return new Response(result: 'ok', id: 123); }
    },
];

// Example minimal container wrapper for the static map
$container = new class($map) implements ContainerInterface {
    public function __construct(private array $map) {}
    public function has(string $id): bool { return array_key_exists($id, $this->map); }
    public function get(string $id) { return $this->map[$id]; }
};

$server = new Server(new RequestFactory(), $container);
```

### 2) Execute a single request from an array

[](#2-execute-a-single-request-from-an-array)

```
$response = $server->executeArrayRequest([
    'jsonrpc' => '2.0',
    'method' => 'sum',
    'id' => 1,
    'params' => [2, 3],
]);

// $response is Alcedo\JsonRpc\Server\DTO\Response
json_encode($response); // {"jsonrpc":"2.0","result":5,"id":1}
```

### 3) Execute a PSR-7 request (single or batch)

[](#3-execute-a-psr-7-request-single-or-batch)

`Server::executePsrRequest()` will parse the PSR-7 body (JSON) and handle single or batch automatically.

```
use Psr\Http\Message\RequestInterface;

/** @var RequestInterface $psrRequest */
$rpcResponse = $server->executePsrRequest($psrRequest);

// Single request -> Response|null
// Batch request  -> BatchResponse
```

### 4) Notifications (no id)

[](#4-notifications-no-id)

Requests without `id` are treated as notifications and return `null`, though the procedure is executed.

```
$result = $server->executeArrayRequest([
    'jsonrpc' => '2.0',
    'method' => 'notify',
    // no id -> notification
]);
// $result === null
```

### 5) Batch requests

[](#5-batch-requests)

Provide an array of requests; notifications are omitted from the resulting `BatchResponse`.

```
$rpcResponse = $server->executePsrRequest($psrRequest); // body contains JSON array
// $rpcResponse is Alcedo\JsonRpc\Server\DTO\BatchResponse and is countable
```

How it works
------------

[](#how-it-works)

Core types under `Alcedo\JsonRpc\Server\DTO`:

- `Request` — JSON-RPC request with method, params, optional id. Validates method names do not start with the reserved `rpc.` prefix.
- `Response` — JSON-RPC response carrying either `result` or `error` (never both). Provides helpers `isError()`/`isSuccess()`.
- `Error` — JSON-RPC error with `code`, `message`, and optional `data`.
- `BatchRequest` — Array-like collection of `Request` or `Error` items. Validates element types.
- `BatchResponse` — Array-like collection of `Response` items. Validates element types.
- `ErrorCodes` — Enum for standard JSON-RPC error codes and server error range.
- `JsonRpcTrait` — Provides `jsonRpc()` returning protocol version `2.0`.

Factories:

- `RequestFactory` — Builds `Request`/`BatchRequest` from PSR-7 request body or arrays. Maps invalid items within a batch to `Error` entries.
- `ErrorFactory` — Convenience constructors for errors: parse, invalid request, method not found, invalid params, internal error, server error.

Server:

- `Server` — Executes requests using a PSR Container to resolve procedures by method name. Supports:
    - `executeArrayRequest(array $request): Response|BatchResponse|null`
    - `executePsrRequest(RequestInterface $request): Response|BatchResponse|null`
    - `execute(Request|BatchRequest $request): Response|BatchResponse|null`

Procedures:

- `RemoteProcedureInterface` — Implement `call(): Response` to provide fully controlled JSON-RPC responses from objects.
- Callables — Any PHP callable is allowed; its return value becomes `result` and exceptions are converted to `internal error`.

Error handling
--------------

[](#error-handling)

The server adheres to JSON-RPC 2.0 error semantics using `ErrorCodes` and `ErrorFactory`:

- `PARSE_ERROR (-32700)` — Invalid JSON in PSR-7 body.
- `INVALID_REQUEST (-32600)` — Missing or malformed fields (e.g., missing `method`).
- `METHOD_NOT_FOUND (-32601)` — Procedure missing in the container.
- `INVALID_PARAMS (-32602)` — For parameter issues (factory available, not auto-generated by server).
- `INTERNAL_ERROR (-32603)` — Exceptions thrown by callables are wrapped with the original message.
- `SERVER_ERROR (-32099…-32000)` — Generic server-side errors (e.g., non-callable procedure), produced with `ErrorFactory::serverError()`.

Transformations and exceptions:

- `ErrorException::fromErrorCode()` can be turned into an `Error` via `$exception->toError()`.
- `InvalidResponseException` — Thrown if a `Response` is constructed with both `result` and `error`.
- `InvalidBatchElementException` — Thrown when invalid items appear in batch collections.
- `InvalidMethodNameException` — Thrown when a `Request` method starts with `rpc.`.

Examples
--------

[](#examples)

### Callable procedure

[](#callable-procedure)

```
$server = new Server(new RequestFactory(), $container);
$response = $server->executeArrayRequest([
    'jsonrpc' => '2.0', 'method' => 'sum', 'id' => 1, 'params' => [10, 5]
]);
// Response(result: 15, id: 1)
```

### Object procedure (RemoteProcedureInterface)

[](#object-procedure-remoteprocedureinterface)

```
class HelloProc implements RemoteProcedureInterface {
    public function call(): Response { return new Response(result: 'hello', id: 7); }
}

$map = ['hello' => new HelloProc()];
$server = new Server(new RequestFactory(), new ArrayContainer($map));
$response = $server->executeArrayRequest(['jsonrpc' => '2.0', 'method' => 'hello', 'id' => 7]);
// Response(result: 'hello', id: 7)
```

### Batch via PSR-7 request

[](#batch-via-psr-7-request)

```
$body = json_encode([
    ['jsonrpc' => '2.0', 'method' => 'sum', 'id' => 1, 'params' => [1, 2]],
    ['jsonrpc' => '2.0', 'method' => 'hello', 'id' => 2],
    ['jsonrpc' => '2.0', 'method' => 'notify'], // notification => omitted in response
]);

$psrRequest = new \GuzzleHttp\Psr7\Request('POST', '/', [], $body);
$batch = $server->executePsrRequest($psrRequest); // BatchResponse
```

Notes and caveats
-----------------

[](#notes-and-caveats)

- RemoteProcedureInterface::call() accepts no parameters; if you need params, you can add them to the implementing class with default values.
- Notifications (no id) return null but still execute the target procedure.
- Batch responses exclude notifications by design, as per JSON-RPC 2.0.
- `Request` rejects method names starting with `rpc.` to reserve the prefix for internal use.

Development
-----------

[](#development)

Run tests with PHPUnit:

```
vendor/bin/phpunit

```

Coding standards:

- PHP\_CodeSniffer (PSR-12) via `vendor/bin/phpcs`
- PHPMD via `vendor/bin/phpmd`

License
-------

[](#license)

MIT License. See `LICENSE` for details.

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance68

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

8

Last Release

187d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/17f01e0508523e3aec1cb2954e6180aa8aa222bc6aea0cec1e156fc8caf6a435?d=identicon)[kiril\_savchev](/maintainers/kiril_savchev)

---

Top Contributors

[![savchev](https://avatars.githubusercontent.com/u/756443?v=4)](https://github.com/savchev "savchev (85 commits)")

---

Tags

jsonjson-rpcjson-rpc-serverphpphp8php82rpc

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/alcedo-json-rpc-server/health.svg)

```
[![Health](https://phpackages.com/badges/alcedo-json-rpc-server/health.svg)](https://phpackages.com/packages/alcedo-json-rpc-server)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[thecodingmachine/graphqlite

Write your GraphQL queries in simple to write controllers (using webonyx/graphql-php).

5723.1M30](/packages/thecodingmachine-graphqlite)[algolia/algoliasearch-client-php

API powering the features of Algolia.

69433.0M114](/packages/algolia-algoliasearch-client-php)[php-heroku-client/php-heroku-client

A PHP client for the Heroku Platform API

24404.8k4](/packages/php-heroku-client-php-heroku-client)[rubix/server

Deploy your Rubix ML models to production with scalable stand-alone inference servers.

632.3k](/packages/rubix-server)[yoti/yoti-php-sdk

Yoti SDK for quickly integrating your PHP backend with Yoti

27539.9k1](/packages/yoti-yoti-php-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
