0.4.7
Very basic gRPC implementation for Deno
Repository
Current version released
2 years ago
/x/grpc_basic
⚠️ You probably should wait for more mature and standard aligned implementation beacuse:
- This lib doesn’t use Deno’s 1.9 HTTP/2 native bindings, but relies on JS implementation roughly ported from node-http2
- I’m not an expert in gRPC or HTTP/2, I just moved HTTP/2 frames around until it worked
- It was never meant for production use, only for fun and some integration tests and scripts
- I have no plans on implementing full gRPC spec
goals - keep it simple
- load proto files
-
server
unary calls -
client
unary calls - multiplex calls
-
server
server streams -
client
server streams - auto reconnects (without retries)
- deadlines/cancellation with AbortController/AbortSignal
- call metadata
- logging interface
non goals - gRPC bloat
- no TLS
- no client streams
- no bidirectional streams
- no client side load balancing
hello world
greeter.proto
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc ShoutHello (HelloRequest) returns (stream HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
greeter.d.ts
Service typings are not essential, but it’s nice to have them
$ deno run --allow-read https://deno.land/x/grpc_basic@0.4.7/gen/dts.ts ./greeter.proto > ./greeter.d.ts
export interface Greeter {
SayHello(request: HelloRequest): Promise<HelloReply>;
ShoutHello(request: HelloRequest): AsyncGenerator<HelloReply>;
}
export interface HelloRequest {
name?: string;
}
export interface HelloReply {
message?: string;
}
server.ts
import { GrpcServer } from "https://deno.land/x/grpc_basic@0.4.7/server.ts";
import { Greeter } from "./greeter.d.ts";
const port = 50051;
const server = new GrpcServer();
const protoPath = new URL("./greeter.proto", import.meta.url);
const protoFile = await Deno.readTextFile(protoPath);
server.addService<Greeter>(protoFile, {
async SayHello({ name }) {
const message = `hello ${name || "stranger"}`;
return { message };
},
async *ShoutHello({ name }) {
for (const n of [0, 1, 2]) {
const message = `hello ${name || "stranger"} #${n}`;
yield { message };
}
}
});
console.log(`gonna listen on ${port} port`);
for await (const conn of Deno.listen({ port })) {
server.handle(conn);
}
client.ts
import { getClient } from "https://deno.land/x/grpc_basic@0.4.7/client.ts";
import { Greeter } from "./greeter.d.ts";
const protoPath = new URL("./greeter.proto", import.meta.url);
const protoFile = await Deno.readTextFile(protoPath);
const client = getClient<Greeter>({
port: 50051,
root: protoFile,
serviceName: "Greeter",
});
/* unary calls */
console.log(await client.SayHello({ name: "unary #1" }));
console.log(await client.SayHello({ name: "unary #2" }));
/* server stream */
for await (const reply of client.ShoutHello({ name: "streamed" })) {
console.log(reply);
}
client.close();