Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/timonson/gentle_rpc
JSON-RPC 2.0 library with HTTP and WebSockets support for deno and the browser
https://github.com/timonson/gentle_rpc
browser deno esmodules fetch javascript json-rpc2 rpc typescript websocket websockets
Last synced: about 1 month ago
JSON representation
JSON-RPC 2.0 library with HTTP and WebSockets support for deno and the browser
- Host: GitHub
- URL: https://github.com/timonson/gentle_rpc
- Owner: timonson
- License: mit
- Created: 2020-03-09T01:34:30.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-05-18T17:27:46.000Z (6 months ago)
- Last Synced: 2024-05-23T10:12:39.342Z (6 months ago)
- Topics: browser, deno, esmodules, fetch, javascript, json-rpc2, rpc, typescript, websocket, websockets
- Language: TypeScript
- Homepage:
- Size: 228 KB
- Stars: 45
- Watchers: 2
- Forks: 9
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# gentle_rpc
JSON-RPC 2.0 library (server and client) with HTTP and WebSockets support for
[deno](https://github.com/denoland/deno) and the browser.### Important Notice
The **gentle_rpc** library is no longer maintained. Please switch to our new and
improved RPC library, **schicksal**, available at
[schicksal on GitHub](https://github.com/Zaubrik/schicksal).## Server
### respond
Takes `Methods`, `ServerRequest` and `Options`. Look
[here](https://github.com/timonson/gentle_rpc/blob/master/server/response.ts)
for more information about `Options`.```typescript
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { respond } from "https://deno.land/x/gentle_rpc/mod.ts";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(" "),
};serve((req) => respond(rpcMethods, req), { addr: ":8000" });
console.log("Listening on http://localhost:8000");
```#### CustomError
Throw a `CustomError` to send a server-defined error response.
```typescript
import { CustomError, respond } from "https://deno.land/x/gentle_rpc/mod.ts";//..
await respond(
{
throwError: () => {
throw new CustomError(
-32040, // the JSON-RPC error code. Note, must be -32040 to -32099
"An error occurred", // the error message, a short sentence
{ details: "..." }, // optional additional details, can be any `JsonValue`
);
},
},
req,
);
//..
```## Client
#### createRemote
Takes a `Resource` for HTTP or a `WebSocket` for WebSockets and returns
`Remote`.```typescript
import { createRemote } from "https://deno.land/x/gentle_rpc/mod.ts";
// Or import directly into the browser with:
import { createRemote } from "https://cdn.jsdelivr.net/gh/timonson/[email protected]/client/dist/remote.js";// HTTP:
const remote = createRemote("http://0.0.0.0:8000");// WebSocket:
const remote = await createRemote(new WebSocket("ws://0.0.0.0:8000"));
```### HTTP
#### call
Takes a string and an `Array` or `Record` object
and returns `Promise`.```typescript
const greeting = await remote.call("sayHello", ["World"]);
// Hello Worldconst namedParams = await remote.call("callNamedParameters", {
a: 5,
b: 10,
c: "result:",
});
// result: 50
```##### notification
Using the option `{ isNotification: true }` will retun `Promise`.
```typescript
const notification = await remote.call("sayHello", ["World"], {
isNotification: true,
});
// undefined
```##### jwt
Adding the option `{jwt: string}` will set the `Authorization` header to
`` `Bearer ${jwt}` ``.```typescript
const user = await remote.call("login", undefined, { jwt });
// Bob
```#### batch
```typescript
const noise1 = await remote.batch([
{
animalsMakeNoise: [
["miaaow"],
["wuuuufu", "wuuuufu"],
["iaaaiaia", "iaaaiaia", "iaaaiaia"],
["fiiiiire"],
],
sayHello: [["World"], undefined, ["World"]],
},
]);
// [ "MIAAOW", "WUUUUFU WUUUUFU", "IAAAIAIA IAAAIAIA IAAAIAIA", "FIIIIIRE", "Hello World", "Hello ", "Hello World" ]
```The following example 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.```typescript
let noise2 = 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" }
```### WebSockets
#### call
Takes a string and an `Array` or `Record` object
and returns `Promise`.```typescript
const noise = await remote.call("callNamedParameters", {
a: 10,
b: 20,
c: "The result is:",
});
// The result is: 200remote.socket.close();
```Notifications return `Promise`.
##### notification
```typescript
const notification = await remote.call("animalsMakeNoise", ["wuufff"], {
isNotification: true,
});
// undefined
```##### messaging between multiple clients
By using the `subscribe` method you can send messages between multiple clients.
It returns an object with a generator property
`{ generator: AsyncGenerator}` and the methods `emit` and
`unsubscribe`.Other clients can _listen to_ and _emit_ messages by _subscribing_ to the same
method.```typescript
const firstClient = await createRemote(new WebSocket("ws://0.0.0.0:8000"));
const secondClient = await createRemote(new WebSocket("ws://0.0.0.0:8000"));async function run(iter: AsyncGenerator) {
try {
for await (let x of iter) {
console.log(x);
}
} catch (err) {
console.log(err.message, err.code, err.data);
}
}const greetingFirst = firstClient.subscribe("sayHello");
const greetingSecond = secondClient.subscribe("sayHello");run(greetingFirst.generator);
run(greetingSecond.generator);
greetingFirst.emit(["first"]);
greetingSecond.emit(["second"]);
// Hello first
// Hello first
// Hello second
// Hello second
```## Proxy API
Optionally, you can import _syntactical sugar_ and use a more friendly API
supported by `Proxy` objects.```typescript
import {
createRemote,
HttpProxy,
httpProxyHandler,
} from "https://deno.land/x/gentle_rpc/mod.ts";const remote = new Proxy(
createRemote("http://0.0.0.0:8000"),
httpProxyHandler,
);let greeting = await remote.sayHello(["World"]);
// Hello Worldconst namedParams = await remote.callNamedParameters({
a: 5,
b: 10,
c: "result:",
});
// result: 50
```## Examples and Tests
Please checkout the
[examples](https://github.com/timonson/gentle_rpc/tree/master/examples) and
[tests](https://github.com/timonson/gentle_rpc/tree/master/tests) folders for
more detailed examples.## Contribution
Every kind of contribution to this project is highly appreciated.\
Please run `deno fmt` on the changed files before making a pull request.