{"id":13401,"library":"json-rpc-2.0","title":"JSON-RPC 2.0 Client and Server","description":"The `json-rpc-2.0` package provides a robust, protocol-agnostic implementation of the JSON-RPC 2.0 specification for both client and server applications. It is designed to work seamlessly in Node.js and browser environments, offering first-class TypeScript support through its strongly typed interfaces. The current stable version is 1.7.1, with releases occurring periodically, often driven by new feature additions or minor bug fixes, as seen in the recent 1.7.x releases. A key differentiator is its zero-dependency philosophy, keeping the package lean and avoiding 'dependency hell'. It focuses purely on the JSON-RPC protocol, allowing developers to choose their preferred underlying transport (HTTP, WebSocket, TCP, etc.) without library constraints, making protocol migrations straightforward. It offers features like middleware for request/response interception and custom parameter injection for concerns like authentication.","status":"active","version":"1.7.1","language":"javascript","source_language":"en","source_url":"https://github.com/shogowada/json-rpc-2.0","tags":["javascript","json-rpc","typescript"],"install":[{"cmd":"npm install json-rpc-2.0","lang":"bash","label":"npm"},{"cmd":"yarn add json-rpc-2.0","lang":"bash","label":"yarn"},{"cmd":"pnpm add json-rpc-2.0","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"While CommonJS `require` works for older Node.js setups, ESM `import` is the idiomatic way for modern JavaScript and TypeScript projects. This package ships ES modules.","wrong":"const { JSONRPCServer } = require('json-rpc-2.0');","symbol":"JSONRPCServer","correct":"import { JSONRPCServer } from 'json-rpc-2.0';"},{"note":"`JSONRPCClient` is a named export, not a default export. Ensure you use destructuring for import.","wrong":"import JSONRPCClient from 'json-rpc-2.0';","symbol":"JSONRPCClient","correct":"import { JSONRPCClient } from 'json-rpc-2.0';"},{"note":"Useful for manually constructing standardized JSON-RPC error responses, especially within middleware or custom error handling logic.","wrong":"const createJSONRPCErrorResponse = require('json-rpc-2.0').createJSONRPCErrorResponse;","symbol":"createJSONRPCErrorResponse","correct":"import { createJSONRPCErrorResponse } from 'json-rpc-2.0';"},{"note":"Introduced in v1.4.0, this class provides a structured way to throw JSON-RPC specific errors with `code`, `message`, and `data` properties that will be correctly formatted in the response.","symbol":"JSONRPCErrorException","correct":"import { JSONRPCErrorException } from 'json-rpc-2.0';"}],"quickstart":{"code":"import express from 'express';\nimport bodyParser from 'body-parser';\nimport { JSONRPCServer, JSONRPCClient } from 'json-rpc-2.0';\nimport fetch from 'node-fetch'; // For client in Node.js\n\n// --- Server Setup ---\nconst server = new JSONRPCServer();\n\nserver.addMethod('echo', ({ text }) => text);\nserver.addMethod('add', ({ a, b }) => a + b);\nserver.addMethod('log', ({ message }) => console.log(message));\n\n// Add a middleware for logging\nserver.applyMiddleware(async (next, request, serverParams) => {\n  console.log(`[Server Middleware] Received request: ${JSON.stringify(request)}`);\n  const response = await next(request, serverParams);\n  console.log(`[Server Middleware] Responding: ${JSON.stringify(response)}`);\n  return response;\n});\n\nconst app = express();\napp.use(bodyParser.json());\n\napp.post('/json-rpc', (req, res) => {\n  const jsonRPCRequest = req.body;\n  server.receive(jsonRPCRequest).then((jsonRPCResponse) => {\n    if (jsonRPCResponse) {\n      res.json(jsonRPCResponse);\n    } else {\n      res.sendStatus(204); // Notification, no response needed\n    }\n  });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`JSON-RPC server listening on http://localhost:${PORT}/json-rpc`));\n\n// --- Client Setup ---\nconst client = new JSONRPCClient(async (jsonRPCRequest) => {\n  const response = await fetch('http://localhost:3000/json-rpc', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify(jsonRPCRequest),\n  });\n  if (response.status === 204) {\n    return; // Notification, no response\n  }\n  const jsonRPCResponse = await response.json();\n  client.receive(jsonRPCResponse);\n});\n\n// --- Client Usage ---\nasync function runClient() {\n  try {\n    console.log('\\n--- Client Calls ---');\n\n    const echoResult = await client.request('echo', { text: 'Hello JSON-RPC' });\n    console.log('Echo result:', echoResult);\n\n    const addResult = await client.request('add', { a: 5, b: 3 });\n    console.log('Add result:', addResult);\n\n    // Send a notification (no response expected)\n    client.notify('log', { message: 'Client sent a log message.' });\n\n    console.log('\\n--- Client finished ---');\n  } catch (error) {\n    console.error('Client error:', error);\n  }\n}\n\n// Give server a moment to start\nsetTimeout(runClient, 1000);","lang":"typescript","description":"This quickstart sets up a basic JSON-RPC 2.0 server using Express and a corresponding client. It demonstrates adding methods, applying middleware for request logging, handling both requests and notifications, and making typed calls from the client. It uses `node-fetch` for HTTP communication, illustrating the protocol-agnostic nature of the library."},"warnings":[{"fix":"Ensure that any errors thrown within JSON-RPC methods are instances of `Error` or `JSONRPCErrorException`. For custom error information, use `JSONRPCErrorException` which provides `code`, `message`, and `data` properties.","message":"In `v1.4.0`, there was a breaking change introduced where errors thrown by RPC methods were expected to be `Error` objects for their `message` to be correctly mapped into the JSON-RPC error response. This might break existing implementations that throw plain strings or custom non-Error objects directly.","severity":"breaking","affected_versions":"1.4.0"},{"fix":"Always check `if (jsonRPCResponse)` before attempting to send the response. If `jsonRPCResponse` is `null`, it indicates a notification, and you should respond with `res.sendStatus(204)` (for HTTP) or similar 'no content' mechanism for your protocol.","message":"When handling JSON-RPC notifications (requests without an `id`), the `server.receive()` method will return a `Promise<null | JSONRPCResponse>`. It's crucial to check for `null` and respond with an appropriate status code (like 204 No Content for HTTP) rather than attempting to send a response payload, as the client does not expect one.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Carefully implement the `sender` function for `JSONRPCClient` and the `receive` call on `JSONRPCServer` to correctly send and receive raw JSON-RPC payloads over your chosen transport. Consider message framing for stream-based protocols like WebSockets or TCP.","message":"The `JSONRPCServer` and `JSONRPCClient` are protocol-agnostic. This means you are responsible for integrating them with your chosen transport layer (e.g., HTTP, WebSockets, TCP). The examples commonly use HTTP for demonstration, but you must implement the request and response transmission according to your specific communication protocol.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always `await` the result of `server.receive()` and ensure that any methods added via `server.addMethod()` correctly return the final result or a `Promise` that resolves to the result. Use `try...catch` blocks within your methods to gracefully handle synchronous and asynchronous errors.","message":"Incorrectly handling asynchronous operations within JSON-RPC methods can lead to unhandled promise rejections or unexpected results. All methods added to `JSONRPCServer` can return a `Promise`, and `server.receive` also returns a `Promise`. Failure to `await` or `then()` these promises can lead to race conditions or incorrect error propagation.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"For ES Modules (modern Node.js and TypeScript), use `import { JSONRPCServer } from 'json-rpc-2.0';`. If forced to use CommonJS `require`, ensure you destructure correctly: `const { JSONRPCServer } = require('json-rpc-2.0');`.","cause":"Attempting to use `require` on a package that primarily provides ES modules with named exports, or incorrect destructuring in ES module syntax.","error":"TypeError: JSONRPCServer is not a constructor"},{"fix":"Ensure `server.receive(jsonRPCRequest).then(...)` or `await server.receive(jsonRPCRequest)` is used. Also, make sure that errors thrown by your RPC methods are either `Error` objects or instances of `JSONRPCErrorException` (v1.4.0+) to allow the server to correctly format them.","cause":"The `server.receive()` call was not `await`-ed or `then()`-ed, leading to a promise being rejected without a handler, or an error thrown within a method was not caught and formatted.","error":"UnhandledPromiseRejectionWarning: Unhandled promise rejection."},{"fix":"On the server, ensure that for any JSON-RPC *request* (payload has an `id`), a `jsonRPCResponse` is always generated and sent back to the client. Only send 204 No Content for JSON-RPC *notifications* (payload lacks an `id`). Check server logs for errors during request processing.","cause":"This error often occurs on the client side when the server failed to send a response for a request (e.g., sent 204 No Content for a request, not a notification) or the network request itself failed.","error":"Expected to receive a JSON-RPC response, but none was provided."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null}