feat(handler): new defineJsonRpcHandler and defineJsonRpcWebSocketHandler#1180
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Deploying h3dev with
|
| Latest commit: |
4d0d8c0
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d4d2748b.h3dev.pages.dev |
| Branch Preview URL: | https://feat-json-rpc-handler.h3dev.pages.dev |
jsonRpcHandlerdefineJsonRpcHandler
|
Hi dear @sandros94 This PR is under my radar (and important!) but have to delay for more testing. In meantime you don't need to keep it updated ❤️ |
Absolutely no problem, I also imagine that we all took some time off for the summer and should focus on more important things first, this is a long term one. This feature is also easy to implement in downstream projects, so no rush. The reason why I kept updating it for a bit was because while testing it with some Json RPC clients (mainly MCP-related ones) I've found a couple of issues and DX improvements, but now it is complete for what I know atm |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@test/json-rpc.test.ts`:
- Line 242: Update the test title string in the it(...) call that currently
reads "should handler primitive thrown errors and map to JSON-RPC error" to the
correct wording "should handle primitive thrown errors and map to JSON-RPC
error" (the test case in test/json-rpc.test.ts containing the it(...)
declaration).
🧹 Nitpick comments (1)
test/json-rpc.test.ts (1)
468-658: LGTM — HTTP error code mapping tests are comprehensive.All major HTTP-to-JSON-RPC mappings are verified. Consider adding tests for 408 (timeout) and 422 (unprocessable entity) if those paths are expected to be exercised by consumers.
|
Development note: with dc503c0 I've dropped support for ReadableStream, something I've missinterpreted in my original implementation last august. The JSON-RPC 2.0 spec expect a single, full, JSON object. It is the MCP spec that allows to have a GET endpoint on the same path which optionally supports ReadableStreams (eg: for server-to-client notifications), meaning it is out of scope from current PR |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@test/json-rpc.test.ts`:
- Around line 233-253: The test currently expects non-HTTP exceptions (thrown by
the "error" handler) to surface error_.message as the JSON-RPC error.data, which
may leak internal details; update the JSON-RPC error mapping logic (the code
that builds the response in the eventHandler/error-to-JSON-RPC converter) so it
only includes error_.message in the "data" field when the error is an HTTPError
(or another explicitly safe error type) or when a configurable
“exposeErrorMessages” flag is enabled; otherwise omit the data field (or replace
with a generic value). Ensure the change references the existing mapping code
that checks error_ (the same place tested by the "should handle handler errors
and map to JSON-RPC error" test) and either adjust the test expectations or add
documentation/config to allow opt-in exposure.
🧹 Nitpick comments (1)
src/utils/json-rpc.ts (1)
54-57:JsonRpcMethodreceives the fullJsonRpcRequestbut the docstring says "parameters".The type signature passes
data: JsonRpcRequest<I>(the full request object includingjsonrpc,method,id, andparams), but the JSDoc on Line 52 says "It receives the parameters from the request." This is accurate for how handlers destructure{ params }in practice, but the first argument namedatais the entire request object, not just params.Consider renaming the parameter from
datatorequest(orreq) for clarity, since that's what it actually is.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@test/json-rpc-ws.test.ts`:
- Around line 180-189: The test name is misleading: it asserts a PARSE_ERROR but
is titled "...Invalid Request"; either change the implementation in
processJsonRpcBody to return INVALID_REQUEST for parsed non-object values
or—simpler—rename the test case to reflect the asserted behavior (e.g., change
the it description to "should return Parse error for non-object body") so the
test name matches the expected PARSE_ERROR (-32700) result; update only the test
description string in json-rpc-ws.test.ts and leave the assertion (error code
and message) as-is if you choose the rename approach.
🧹 Nitpick comments (2)
src/utils/json-rpc.ts (1)
389-395:methodis typed asunknown— may cause TypeScript errors on strict configs.
req.methodresolves tounknown(fromRecord<string, unknown>), but it's used as astringindex intomethodMap(line 395) and assigned toJsonRpcRequest.method(line 404). By this point, line 363 has already validatedtypeof req.method === "string", so the value is safe at runtime, but TypeScript doesn't narrow across the conditional into a separate variable assignment.Consider adding a cast:
const method = req.method as string;Proposed fix
- const method = req.method; + const method = req.method as string;test/json-rpc-ws.test.ts (1)
329-350: InnersendMessageshadows the outer helper — acceptable but worth noting.The
sendMessagein the "batch requests"describeblock shadows the one in "message processing". This is fine since they have different method registrations, but if moredescribeblocks are added, consider extracting a shared configurable helper to reduce duplication.
defineJsonRpcHandlerdefineJsonRpcHandler and defineJsonRpcWebSocketHandler
`createJsonRpcError` was dropping valid falsy `data` values (0, "", false). `isValidId` was accepting NaN, Infinity, and fractional numbers which serialize to null in JSON, silently corrupting the response id. Co-Authored-By: Claude Opus 4.6 <[email protected]>
An experimental handler to support the JSON RPC spec.
Usage
you define it like a normal handler, but with the added
paramsas its first callback argument:then you call it with a valid body, for example:
{ "jsonrpc": "2.0", "id": 1, "method": "echo", "params": ["Hello World"], }and you'll receive a json-rpc compatible response:
{ "jsonrpc": "2.0", "id": 1, // Same id from the request "result": "Received `Hello World` on path `/rpc`", }it also support client-to-server notifications by simply omitting the
idkey, this will result in the server responding a202Personal considerations and future expansion
Summary by CodeRabbit
New Features
Tests
Style