7.12.3. JSONRPC-03 — §6 Batches: Many Messages in One Wire
This tutorial covers JSON-RPC 2.0 §6 batch requests — sending and
receiving multiple messages in a single wire payload. The semantics
are subtle (empty array is an error, all-notifications batch yields
nothing on the wire, per-entry errors are individual envelopes), but
daslib/jsonrpc handles all the edge cases.
7.12.3.1. Mixed batch round-trip
A client batches two requests plus one notification. The server dispatches them. The response is an array of two entries: the notification produces no response and input order is preserved.
let entries <- [
make_request("ping", "null", 1),
make_notification("log", "\{\"msg\":\"hello\"}"),
make_request("echo", "[42]", 2)
]
let wire = make_batch(entries)
let resp = jsonrpc::dispatch_line(wire, false) $(m, p) {
if (m == "ping") return "\"pong\""
if (m == "echo") return jsonrpc::compact_json_whitespace(p)
return "\"unknown\""
}
// resp = [{"id":1,"result":"pong"},{"id":2,"result":[42]}]
7.12.3.2. Per-entry errors: continue-on-error
Malformed entries — missing method, bad id type, etc. — get individual error envelopes in their array slot. Valid entries still dispatch:
let wire = "[\{\"id\":1,\"method\":\"ping\"},\{\"id\":2},\{\"id\":3,\"method\":\"echo\",\"params\":[\"x\"]}]"
let resp = jsonrpc::dispatch_line(wire, false) $(m, p) { return "ok" }
// resp has three entries:
// id=1 result
// id=2 error -32600 (missing method)
// id=3 result
7.12.3.3. Empty batch array
Per §6, an empty array [] is itself an invalid request. The server
responds with a SINGLE error envelope, not an array:
let resp = jsonrpc::dispatch_line("[]", false) $(m, p) { return "" }
// resp = {"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"invalid request: empty batch"}}
7.12.3.4. All-notifications batch
If every entry in a batch is a notification, the server processes them (dispatcher runs for each) but emits nothing on the wire — the response array would be empty, so per §6 the server returns nothing at all:
let wire = "[\{\"method\":\"a\"},\{\"method\":\"b\"}]"
let resp = jsonrpc::dispatch_line(wire, false) $(m, p) { return "ignored" }
// resp == ""
7.12.3.5. Manual batch handling
For custom error semantics (per-method INVALID_PARAMS,
METHOD_NOT_FOUND, logging per entry, etc.), use parse_batch
directly:
let pb = parse_batch(wire)
if (!empty(pb.framing_error)) return pb.framing_error
for (req in pb.requests) {
if (!empty(req.error_envelope)) { /* per-entry error */ }
else { /* req.method, req.id_str, req.params, req.params_json available */ }
}
7.12.3.6. Running the tutorial
daslang.exe tutorials/jsonrpc/03_batch.das
Full source: tutorials/jsonrpc/03_batch.das
7.12.3.7. See also
JSONRPC-01 — Building Requests, Parsing Responses — building requests, parsing responses
JSONRPC-02 — Implementing a Server with dispatch_line — server with
dispatch_lineJSON-RPC 2.0 envelope + parser, transport-agnostic — module reference