【问题标题】:How do you generate typings for protobuf files for use with GRPC?您如何为 protobuf 文件生成类型以用于 GRPC?
【发布时间】:2021-02-08 08:02:45
【问题描述】:

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

我已经了解了我在 cmets 中遇到的问题。

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

有关

【问题讨论】:

    标签: node.js typescript protocol-buffers grpc


    【解决方案1】:

    您可以使用 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
    

    这是我用于此示例的 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();
          }
        }
      );
    }
    

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

    【讨论】:

    • 当前的例子(也在你的 github repo 上)已经过时了。该示例使用client.unaryCall,但目前使用的是makeUnaryRequest。你能给我们举个例子吗?谢谢!
    • @Simon Sola 我创建了一个问题来更新示例github.com/badsyntax/grpc-js-typescript/issues/18
    • @SimonSoka 这个例子没有错。 rpc 方法在 proto 文件中定义,因此您的 proto 文件可能具有“makeUnaryRequest”的定义。我已经更新了答案以包含 proto 文件以防止混淆。
    猜你喜欢
    • 2018-09-20
    • 1970-01-01
    • 2020-05-29
    • 2021-04-24
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    相关资源
    最近更新 更多