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

Laminas Json Server Laravel Package

laminas/laminas-json-server

Laminas JSON Server provides a JSON-RPC server implementation for Laminas applications, enabling PHP classes and services to be exposed as JSON-RPC endpoints with request handling, method dispatch, error responses, and MVC integration.

Deep Wiki
Context7

Getting Started

This is not a Laravel package — it's a Laminas component that implements a JSON-RPC 2.0 server (Laminas\Json\Server\Server). You get protocol handling, request parsing, error mapping, and optional service-map (SMD) generation; you bring the transport (a route/controller) and the business logic.

  1. Install:

    composer require laminas/laminas-json-server
    

    Expect laminas/laminas-json, laminas/laminas-eventmanager, laminas/laminas-stdlib, and (legacy) laminas/laminas-http to come along. Check the PHP constraint against your app before committing.

  2. Look first at Laminas\Json\Server\Server — specifically addFunction(), setClass(), setRequest(), handle(), and getResponse(). Everything else is glue.

  3. Minimal wiring — one POST route, one class of methods:

    // routes/api.php
    Route::post('/rpc', RpcController::class);
    
    // app/Http/Controllers/RpcController.php
    public function __invoke(Request $request)
    {
        $server = new \Laminas\Json\Server\Server();
        $server->setClass(app(\App\Rpc\UserApi::class), 'user');
        $server->setClass(app(\App\Rpc\OrderApi::class), 'order');
    
        $server->handle($request->getContent()); // raw body, not the Request object
    
        return response($server->getResponse()->toJson(), 200)
            ->header('Content-Type', 'application/json');
    }
    
  4. First real use case: expose a handful of internal service methods (user.find, order.cancel) to a partner or internal SPA without designing a full REST surface. The dot-namespacing from setClass($obj, 'user') is the whole API design.

  5. Verify with:

    curl -X POST http://app.test/api/rpc \
      -H 'Content-Type: application/json' \
      -d '{"jsonrpc":"2.0","method":"user.find","params":{"id":1},"id":1}'
    

Implementation Patterns

Class-per-namespace, resolved through the container. The single most important pattern: resolve the API class via app() and pass the instance to setClass(), not the class-string — otherwise the library instantiates it itself and your constructor injection (repositories, services, config) never runs.

$server->setClass(app(\App\Rpc\UserApi::class), 'user');
// exposes user.create, user.update, user.find, ...

Closures for one-offs. addFunction('ping', fn () => 'pong') is fine for health-check-ish methods, but keep it rare — closures bypass DI and are invisible to the class-based SMD.

Serve an SMD for discovery. If clients are JS, expose the auto-generated service map at a GET sibling route; it's cheap documentation:

Route::get('/rpc/smd', fn () => response()->json($server->getServiceMap()->toArray()));

Cache this response — it's deterministic per deployment and costs reflection to build.

Batch requests. The spec allows JSON arrays of calls; the Laminas server handles a single call. Wrap it:

$payload = json_decode($request->getContent(), true);
if (array_is_list($payload)) {
    $out = [];
    foreach ($payload as $call) {
        $s = clone $server;              // fresh response per call
        $s->handle(json_encode($call));
        $out[] = json_decode($s->getResponse()->toJson(), true);
    }
    return response()->json($out);
}

Auth and permissions belong in middleware, not RPC methods. Use Laravel middleware for authentication, then per-method authorization inside the API classes ($this->authorize('update', $user)). The JSON-RPC layer should stay dumb. Since notifications (no id) and errors both flow through handle(), middleware is the only place that sees the raw payload before dispatch.

Map domain exceptions deliberately. Catch your own exceptions in a thin wrapper around handle() and convert them to JSON-RPC errors with meaningful codes — or throw Laminas\Json\Server\Exception\RuntimeException from methods and let the server encode -32603. Prefer the former; the library's messages leak stack-ish detail and give you no structured data field.

Notification-aware responses. For calls without an id, handle() produces a response that should not be sent. Check $server->getResponse()->isError() / inspect getRequest()->isNotification() (where available) and return 204 No Content — clients that expect empty bodies will break on {"jsonrpc":"2.0","result":null,"id":null}.

Version your method namespaces, not URLs: setClass($obj, 'v1.user') vs setClass($obj, 'v2.user'). This lets old mobile clients keep working while you ship new behaviour on the same endpoint.

Gotchas and Tips

  • Don't pass the Laravel Request. $server->handle() wants the raw JSON string (or a Laminas\Json\Server\Request). Passing $request or $request->all() silently produces "method not found" or empty params. Use $request->getContent().

  • Content-Type matters for some clients. JSON-RPC mandates application/json. Clients sending text/plain may still work because parsing is body-based, but proxies and rate limiters won't classify it as JSON — enforce the header in middleware.

  • CSRF will bite you. routes/api.php is fine; if you put the endpoint in routes/web.php behind VerifyCsrfToken, every client fails with a 419 before reaching the server. Exclude the route or move it.

  • setClass() with a string is a trap. It constructs the class with no arguments. Any class needing a repository will fatal. Always pass app(SomeApi::class).

  • Method resolution is strict. user.find maps to user namespace + find method. No __call, no underscore-to-camel translation, no case folding. A typo yields -32601 with no hint about valid names — log the raw method name during debugging.

  • Parameter shape is on you. The library does not validate params against a schema. Positional params arrive as an array, named params as an assoc array. Normalise at the top of each method (or build a tiny BaseApi with requireParams([...])) so you don't hand-write checks in 30 methods.

  • Batch is not built in. Clone the server or build a fresh one per call in the batch loop; reusing one instance leaks the previous response's error state into the next call.

  • Legacy dependency weight. This pulls the Laminas HTTP/MVC-era stack. Check composer why laminas/laminas-http after install; if it drags in laminas-mvc, you may prefer to isolate it behind an adapter class so you can swap to a lighter JSON-RPC library later without touching business code.

  • Low activity — plan for exit. 15 stars means near-zero issue response. Keep API classes framework-agnostic (plain PHP, no Laminas imports), and keep the transport in one thin controller. The day you replace the library, only that controller changes.

  • Debugging: dump $server->getRequest()->getMethod(), getParams(), and getResponse()->getError() on 500s. Also log the raw body — by far the most common failure is malformed JSON that the client says it sent correctly.

  • SMD exposure is a security decision. The generated service map enumerates every public method, including any you exposed "temporarily." Whitelist via explicit addFunction() calls or gate the SMD route behind auth.

  • Extension point: if you need custom error formatting, subclass Server and override how errors are set on the response, rather than post-processing the JSON string (regex on JSON is a bug factory).

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.
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
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle