alex-kudrya / laravel-jsonrpc
JSON RPC 2.0 for Laravel
Requires
- php: >= 8.2
- illuminate/contracts: >= 10
- illuminate/http: >= 10
- illuminate/support: >= 10
- illuminate/validation: >= 10
- laravel/framework: >= 10
README

{ JSON RPC 2.0 } for Laravel
What is JSON-RPC you can learn here - #JSONRPC
Compatibility
| Package version | PHP | Laravel |
|---|---|---|
v1.x | >=8.2 | ^10.0, ^11.0, ^12.0, ^13.0 |
Laravel 13 is installable only on PHP versions supported by Laravel 13 itself (>=8.3).
Installation
composer require alex-kudrya/laravel-jsonrpc
In app.php add to providers array \AlexKudrya\LaravelJsonRpc\Providers\JsonRpcServiceProvider::class
// config/app.php
'providers' => [
...
\AlexKudrya\LaravelJsonRpc\Providers\JsonRpcServiceProvider::class,
...
]
Publish package to your app
php artisan vendor:publish --provider=AlexKudrya\LaravelJsonRpc\Providers\JsonRpcServiceProvider
You can also publish only specific files:
php artisan vendor:publish --provider=AlexKudrya\LaravelJsonRpc\Providers\JsonRpcServiceProvider --tag=json-rpc-config
php artisan vendor:publish --provider=AlexKudrya\LaravelJsonRpc\Providers\JsonRpcServiceProvider --tag=json-rpc-ai-guidelines
How it works
JSON-RPC API it is an Api with single endpoint, by default it is https://your-domain.com/json-rpc/v1, json-rpc/v1 part can be configured in config/json_rpc.php.
Requests uses always only POST method.
There are exist fixed request - response structure for this protocol.
Example
Request
{
"jsonrpc": "2.0",
"method": "ControllerName@MethodName",
"params": {
"parameter": "value"
},
"id": "some_unique_request_id"
}
Responce
{
"jsonrpc": "2.0",
"result": {
"key": "value"
},
"id": "some_unique_request_id"
}
jsonrpc, method, params, id are required fields for JSON-RPC request
| Field | Description |
|---|---|
| jsonrpc | Just always equal to 2.0, it is constant, dont think about it. |
| method | The method we calling to. |
| params | JSON with input data, can be empty, but must be exist. |
| id | An unique request ID, need for front-end. When you use batch-requests, your front-end need to indentify which responce for which request was returned |
Calling Method consist from these parts:
- Controller name
- Separator
- Method name
Example: User@get\
In this example:
- "User" is a controller name, means
App\Http\Controllers\JsonRpc\UserControllercontroller/class. App\Http\Controllers\JsonRpc it is acontrollers_root_namespacefromconfig/json_rpc.phpfile, and Controller is acontrollers_postfixfromconfig/json_rpc.phpfile. - "@" is a separator,
controllers_method_delimiterfromconfig/json_rpc.phpfile. - "get" means we calling get() method from this controller.
As a result, method User@get calling get() method from App\Http\Controllers\JsonRpc\UserController
Check Server
To check server status you need make this request:
{
"jsonrpc": "2.0",
"method": "ping",
"params": {},
"id": "dlalkmd1231da"
}
If everythig is ok you will receive this responce:
{
"jsonrpc": "2.0",
"result": {
"message": "pong"
},
"id": "dlalkmd1231da"
}
Basic usage
Request:
{
"jsonrpc": "2.0",
"method": "Product@create",
"params": {
"name": "pencil",
"price": "1.5"
},
"id": "lsfkkj3fl3k92202jf2n32k430f"
}
Controller:
// app/Http/Controllers/JsonRpc/ProductController.php
namespace App\Http\Controllers\JsonRpc;
use AlexKudrya\LaravelJsonRpc\Requests\JsonRpcRequest;
use App\Http\Controllers\Controller;
class ProductController extends Controller
{
public function create(JsonRpcRequest $request)
{
$request->params(); // ['name' => 'pencil', 'price' => '1.5']
$request->params('name'); // pencil
$request->param('price'); // 1.5
$request->id(); // lsfkkj3fl3k92202jf2n32k430f
$request->method() // Product@create
$request->method(true) // ["controller" => "Product", "method" => "create"]
// you can use your input params like this:
$product = Product::create([
'name' => $request->params('name'),
'price' => $request->params('price'),
])
// or like this:
$product = Product::create($request->params())
return $product;
}
}
Responce:
{
"jsonrpc": "2.0",
"result": {
"id": "1",
"name": "pencil",
"price": "1.5"
},
"id": "lsfkkj3fl3k92202jf2n32k430f"
}
Atiention
- To use request validation your Request class must extends
AlexKudrya\LaravelJsonRpc\Requests\JsonRpcRequestclass. - Do not use
$request->all()or$request->input()to get your input parameters, you need to use$request->params()or$request->param({key})for this purpose
Auth
route_middleware configures the Laravel middleware stack for the single JSON-RPC endpoint. It accepts a string, an array of any length, or an empty value for a transparent endpoint.
Recommended for new Laravel applications: use standard Laravel middleware for auth. For Sanctum:
// config/json_rpc.php
'route_middleware' => [
'api',
'auth:sanctum',
],
'auth_required' => false,
Middleware is not limited to auth. Add throttling, logging, tenancy, observability, or custom classes in the same array:
'route_middleware' => [
'api',
'auth:sanctum',
'throttle:api',
App\Http\Middleware\JsonRpcLogging::class,
],
Because JSON-RPC uses one route for all methods, route middleware applies to the whole endpoint. To keep the endpoint fully transparent, use:
'route_middleware' => [],
'auth_required' => false,
For backward compatibility, package-level auth is still supported. Set auth_required to true and provide an auth_handler in config/json_rpc.php.
'auth_required' => true,
'auth_handler' => [App\Auth\JsonRpcAuth::class, 'handle'],
Use auth_handler when you need custom JSON-RPC auth or no_auth_methods method-level bypasses while preserving backward compatibility.
Auth handlers may accept only the JSON-RPC input:
public function handle(array $input): bool
or the input and request headers:
public function handle(array $input, array $headers): bool
Use no_auth_methods for public methods such as ping.
Error logging
Set error_logging to true to write JSON-RPC errors to the json_rpc Laravel log channel.
'error_logging' => true,
Swagger / OpenAPI
JSON-RPC must be documented as a single POST endpoint. The RPC method is selected by the JSON body field method, not by the URL.
Use AlexKudrya\LaravelJsonRpc\OpenApi\JsonRpcOpenApi to build an OpenAPI array that can be returned as JSON or passed to your Swagger tooling:
use AlexKudrya\LaravelJsonRpc\OpenApi\JsonRpcOpenApi;
$openapi = JsonRpcOpenApi::document([
JsonRpcOpenApi::method(
method: 'Product@create',
paramsSchema: [
'type' => 'object',
'required' => ['name'],
'properties' => [
'name' => ['type' => 'string'],
'price' => ['type' => 'number'],
],
],
resultSchema: [
'type' => 'object',
'properties' => [
'id' => ['type' => 'integer'],
'name' => ['type' => 'string'],
],
],
options: [
'summary' => 'Create product',
'params_example' => ['name' => 'pencil', 'price' => 1.5],
],
),
], [
'title' => 'Product JSON-RPC API',
'version' => '1.0.0',
]);
The generated schema documents both single requests and batch requests for the same endpoint.
Testing
Use AlexKudrya\LaravelJsonRpc\Testing\JsonRpcRequestTrait in Laravel feature tests:
use AlexKudrya\LaravelJsonRpc\Testing\JsonRpcRequestTrait;
class ProductJsonRpcTest extends TestCase
{
use JsonRpcRequestTrait;
public function test_create(): void
{
$response = $this->jsonRpcRequest(
controller: ProductController::class,
method: 'create',
params: ['name' => 'pencil'],
id: 'request-id',
);
$response->assertOk();
$response->assertJsonPath('jsonrpc', self::RPC_VER);
$response->assertJsonPath('id', 'request-id');
}
}
Batch requests
If you do not need to make several requests in parallel, you can use batch requests. The peculiarity of this type of request is that requests are executed sequentially in the order in which they are located in the request. Keep in mind that the failure of one request does not block the execution of the following requests.
You can use batch requests to send several requests in one:
Request:
[
{
"jsonrpc": "2.0",
"method": "Product@create",
"params": {
"name": "pencil",
"price": "1.5"
},
"id": "lsfkkj3fl3k92202jf2n32k430f"
},
{
"jsonrpc": "2.0",
"method": "Product@create",
"params": {
"name": "pen",
"price": "3.2"
},
"id": "dqsfkfOd2dwkdwo1231dlslawm20"
}
]
Responce:
[
{
"jsonrpc": "2.0",
"result": {
"id": "1",
"name": "pencil",
"price": "1.5"
},
"id": "lsfkkj3fl3k92202jf2n32k430f"
},
{
"jsonrpc": "2.0",
"result": {
"id": "2",
"name": "pen",
"price": "3.2"
},
"id": "dqsfkfOd2dwkdwo1231dlslawm20"
}
]