如何为用于GRPC的protobuf文件生成类型定义?

4

我正在尝试使用TypeScript与GRPC,并努力确保我设置了所有类型(而不仅仅是添加自己的映射或使用any)。

到目前为止,我已经做到了这一点,但我在评论中记录了我遇到的问题。

import { Server, loadPackageDefinition } from "grpc";
import { loadSync } from "@grpc/proto-loader";

const packageDefinition = loadSync(__dirname + "/protos/artifact.proto");
const artifacts = loadPackageDefinition(packageDefinition).artifacts;

// what are the types here?
function SignedUrlPutObject(call, callback) {
}

const server = new Server();
// There's no ArtifactUpload defined in artifacts
server.addService(artifacts.ArtifactUpload.service, { SignedUrlPutObject })

我尝试过的另一种方法是使用pbjspbts

"protobuf": "pbjs -t static-module -w commonjs -o protos.js protos/artifact-upload.proto && pbts -o protos.d.ts protos.js",

我生成了类型文件,但无法与grpc一起使用。这里有一个我发现的可能相关的github问题 https://github.com/protobufjs/protobuf.js/issues/1381

1个回答

14

你可以使用3种主要工具:

  1. ts-protoc-gen
  2. @grpc/proto-loader
  3. grpc_tools_node_protoc_ts

我建议使用proto-loader:

npm i @grpc/proto-loader
你可以这样生成类型:
./node_modules/.bin/proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto

这是我在本例中使用的协议文件:

syntax = "proto3";

package example_package;

message ServerMessage {
  string server_message = 1;
}

message ClientMessage {
  string client_message = 1;
}

service Example {
  rpc unaryCall(ClientMessage) returns (ServerMessage) {}
  rpc serverStreamingCall(ClientMessage) returns (stream ServerMessage) {}
  rpc clientStreamingCall(stream ClientMessage) returns (ServerMessage) {}
  rpc bidirectionalStreamingCall(stream ClientMessage) returns (stream ServerMessage) {}
}

一旦类型生成,您可以这样使用它们:

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { ProtoGrpcType } from './proto/example';
import { ClientMessage } from './proto/example_package/ClientMessage';
import { ExampleHandlers } from './proto/example_package/Example';
import { ServerMessage } from './proto/example_package/ServerMessage';

const host = '0.0.0.0:9090';

const exampleServer: ExampleHandlers = {
  unaryCall(
    call: grpc.ServerUnaryCall<ClientMessage, ServerMessage>,
    callback: grpc.sendUnaryData<ServerMessage>
  ) {
    if (call.request) {
      console.log(`(server) Got client message: ${call.request.clientMessage}`);
    }
    callback(null, {
      serverMessage: 'Message from server',
    });
  },

  serverStreamingCall(
    call: grpc.ServerWritableStream<ClientMessage, ServerMessage>
  ) {
    call.write({
      serverMessage: 'Message from server',
    });
  },

  clientStreamingCall(
    call: grpc.ServerReadableStream<ClientMessage, ServerMessage>
  ) {
    call.on('data', (clientMessage: ClientMessage) => {
      console.log(
        `(server) Got client message: ${clientMessage.clientMessage}`
      );
    });
  },

  bidirectionalStreamingCall(
    call: grpc.ServerDuplexStream<ClientMessage, ServerMessage>
  ) {
    call.write({
      serverMessage: 'Message from server',
    });
    call.on('data', (clientMessage: ClientMessage) => {
      console.log(
        `(server) Got client message: ${clientMessage.clientMessage}`
      );
    });
  },
};

function getServer(): grpc.Server {
  const packageDefinition = protoLoader.loadSync('./proto/example.proto');
  const proto = (grpc.loadPackageDefinition(
    packageDefinition
  ) as unknown) as ProtoGrpcType;
  const server = new grpc.Server();
  server.addService(proto.example_package.Example.service, exampleServer);
  return server;
}

if (require.main === module) {
  const server = getServer();
  server.bindAsync(
    host,
    grpc.ServerCredentials.createInsecure(),
    (err: Error | null, port: number) => {
      if (err) {
        console.error(`Server error: ${err.message}`);
      } else {
        console.log(`Server bound on port: ${port}`);
        server.start();
      }
    }
  );
}

我在这里创建了各种如何使用TypeScript进行gRPC的示例:https://github.com/badsyntax/grpc-js-types


当前的示例(也包括在您的Github存储库中)已经过时。该示例使用client.unaryCall,但目前正在使用的是makeUnaryRequest。您能否为我们提供相应的示例?谢谢! - Simon Soka
1
@Simon Sola,我已经创建了一个问题来更新示例 https://github.com/badsyntax/grpc-js-typescript/issues/18 - badsyntax
@SimonSoka 这个例子没有问题。rpc 方法在 proto 文件中定义,所以你的 proto 文件很可能也定义了 "makeUnaryRequest" 的方法。我已经更新了答案,包括 proto 文件,以防止混淆。 - badsyntax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接