Skip to content

Function: jsonRPCServiceEntrypoint() ​

jsonRPCServiceEntrypoint(options?): EntrypointAdapter<ServiceContext<{ }>>

Create a service adapter of an entrypoint served over JSON-RPC 2.0, on HTTP, WebSocket or stdio. Only the WebSocket transport needs an optional peer dependency, ws; without it, the entrypoint fails to start.

A request's method and named params become the service action's pattern and input: by default {"method": "user.get", "params": {"id": 1}} is dispatched as {method: 'user.get', id: 1} (see JSONRPCMappingOptions for the other mappings). The batches are answered with an array of responses, the notifications (no id) run without a response. The action's result is the response's result (null for none); its error becomes a JSON-RPC error (see JSONRPCErrorCode): METHOD_NOT_FOUND, INVALID_PARAMS for a failed validation, otherwise SERVER_ERROR with the whole error object as its data.

Over HTTP, a message is the body of a POST to the path, answered with 200 and the JSON response (204 when it held only notifications); any other method or path is answered with 404, and the CORS headers allow any origin. Over WebSocket and stdio, the events pushed by Entrypoint.notify and Entrypoint.broadcast are sent as notifications, {"jsonrpc": "2.0", "method": event, "params": args}. The client id carried by ServiceContext.clientId is the id header or id query parameter of the HTTP request or of the WebSocket connection (at most 200 characters; a random one for a WebSocket connection without it), and 'stdio' on stdio.

When an HTTP client disconnects before its response, the action's abort signal fires. When the entrypoint stops, stdio stops reading, the new requests are answered with STOPPING, and once the requests in progress are answered the WebSocket connections are closed (code 1001; the ones not answering within a second are terminated) and the server shuts down, closing its remaining connections (the ones taken over by an upgrade of the application too).

Parameters ​

options? ​

JSONRPCServiceEntrypointOptions

The adapter options; by default it serves HTTP on port 3000 of all the interfaces, on the path /.

Returns ​

EntrypointAdapter<ServiceContext<{ }>>

The adapter, to give to the service option of buildEntrypoints.

Example ​

typescript
import {Application} from 'lakutata'
import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
import {ServiceAction} from 'lakutata/decorator/ctrl'
import {jsonRPCServiceEntrypoint} from 'lakutata/adapter/jsonrpc'
import WebSocket from 'ws'

class UserController extends Controller {
    @ServiceAction({method: 'user.get'})
    public async get(input: {id: number}): Promise<{id: number, name: string}> {
        return {id: input.id, name: 'Ada'}
    }
}

Application.run({
    id: 'user.service',
    name: 'Users',
    components: {
        entrypoint: buildEntrypoints({
            controllers: [UserController],
            service: [
                //POST http://localhost:3000/rpc
                jsonRPCServiceEntrypoint({name: 'rpc-http', port: 3000, path: '/rpc'}),
                //ws://localhost:3001/rpc, with the events pushed
                jsonRPCServiceEntrypoint({name: 'rpc-ws', transport: 'websocket', port: 3001, path: '/rpc'})
            ]
        })
    },
    bootstrap: ['entrypoint']
})

//An HTTP client: {"jsonrpc": "2.0", "id": 1, "result": {"id": 1, "name": "Ada"}}
const response: Response = await fetch('http://localhost:3000/rpc', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({jsonrpc: '2.0', id: 1, method: 'user.get', params: {id: 1}})
})
console.log(await response.json())

//A WebSocket client, identified as client-1: the responses and the notifications arrive as messages
const socket: WebSocket = new WebSocket('ws://localhost:3001/rpc?id=client-1')
socket.on('open', (): void => socket.send(JSON.stringify({jsonrpc: '2.0', id: 2, method: 'user.get', params: {id: 2}})))
socket.on('message', (data: WebSocket.RawData): void => console.log(JSON.parse(data.toString())))

Released under the MIT License.