JSON-RPC 2.0 library with WebSockets and HTTP support for deno and the browser.
This library is accessible through the https://deno.land/x/ service or through https://nest.land/package/gentle_rpc.
Takes a req
, methods
and options
. You can set options for an additional
server argument or public error stacks.
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import { respond } from "https://deno.land/x/gentle_rpc/mod.ts"
const s = serve("0.0.0.0:8000")
console.log("listening on 0.0.0.0:8000")
const rpcMethods = {
sayHello: (w: [string]) => `Hello ${w}`,
callNamedParameters: ({ a, b, c }: { a: number; b: number; c: string }) =>
`${c} ${a * b}`,
animalsMakeNoise: (noise: [string]) =>
noise.map((el) => el.toUpperCase()).join(" "),
}
for await (const req of s) {
// HTTP:
await respond(req, rpcMethods)
// WebSockets:
await respond(req, rpcMethods, { proto: "ws" })
}
Takes a resource
for HTTP or a WebSocket
for WebSockets and returns a
TypeScript Proxy
or Promise<Proxy>
which we will call remote
from now on.
import { createRemote } from "https://deno.land/x/gentle_rpc/mod.ts"
// HTTP:
const remote = createRemote("http://0.0.0.0:8000")
// WebSocket:
const remote = await createRemote(new WebSocket("ws://0.0.0.0:8000"))
All remote
methods take an Array<JsonValue>
or Record<string, JsonValue>
object and return Promise<JsonValue | undefined>
.
const greeting = await remote.sayHello(["World"])
// Hello World
const namedParams = await remote.callNamedParameters({
a: 5,
b: 10,
c: "result:",
})
// result: 50
const notification = await remote.sayHello.notify(["World"])
// undefined
This method will set the Authorization
header to `Bearer ${jwt}`
.
const greeting = await remote.sayHello.auth(jwt)(["World"])
// Hello World
const noise1 = await remote.animalsMakeNoise.batch([
["miaaow"],
["wuuuufu", "wuuuufu"],
["iaaaiaia", "iaaaiaia", "iaaaiaia"],
["fiiiiire"],
])
// [ "MIAAOW", "WUUUUFU WUUUUFU", "IAAAIAIA IAAAIAIA IAAAIAIA", "FIIIIIRE" ]
Takes either a batchObject
or a batchArray
as argument and returns a
promise.
await remote.batch({
cat: ["sayHello", ["miaaow"]],
dog: ["animalsMakeNoise", ["wuuuufu"]],
donkey: ["sayHello"],
dragon: ["animalsMakeNoise", ["fiiiiire", "fiiiiire"]],
})
// { cat: "Hello miaaow", dog: "WUUUUFU", donkey: "Hello ", dragon: "FIIIIIRE FIIIIIRE" }
The example above uses the object keys cat
, dog
, donkey
, dragon
as RPC
request object ids under the hood. The returned RPC result values will be
assigned to these keys.
For other use cases you might prefer the following example:
await remote.batch([
"animalsMakeNoise",
["miaaow"],
["wuuuufu", "wuuuufu"],
["iaaaiaia", "iaaaiaia", "iaaaiaia"],
["fiiiiire"],
])
// [ "MIAAOW", "WUUUUFU WUUUUFU", "IAAAIAIA IAAAIAIA IAAAIAIA", "FIIIIIRE" ]
The support for WebSockets is still experimental and has not been fully tested yet.
All remote
methods take an Array<JsonValue>
or Record<string, JsonValue>
object and return Promise<JsonValue | undefined>
.
const noise = await remote.animalsMakeNoise(["wuufff"])
console.log(noise)
remote.socket.close()
const notification = await remote.animalsMakeNoise.notify(["wuufff"])
By using the subscribe
method you can send messages between multiple clients.
It returns an object with a generator property
{ generator: AsyncGenerator<JsonValue>}
and the methods emit
, emitBatch
and unsubscribe
.
Other clients can listen to and emit messages by subscribing to the same method.
// First client
export async function run(iter: AsyncGenerator<unknown>) {
try {
for await (let x of iter) {
console.log(x)
}
} catch (err) {
console.log(err.message, err.code)
}
}
const greeting = remote.sayHello.subscribe()
run(greeting.generator)
greeting.emit(["first"])
// Hello first
// Hello second
// Hello third
// Second client
const greeting = remote.sayHello.subscribe()
run(greeting.generator)
greeting.emitBatch([["second"], ["third"]])
// Hello first
// Hello second
// Hello third
// You can optionally unsubscribe:
greeting.unsubscribe()
Checkout the examples and tests folders for more detailed examples.
Every kind of contribution to this project is highly appreciated.
Please run deno fmt
on the changed files before making a pull request.