【问题标题】:How to resolve Enums as String values with Node grpc?如何使用 Node grpc 将枚举解析为字符串值?
【发布时间】:2019-10-23 12:59:35
【问题描述】:

将 grpc 与 Node 结合使用,响应我的查询的枚举解析为整数值。但是,当我使用 BloomRPC 进行相同的查询时,枚举解析为整数值。

是否有参数或选项可以强制使用 Node grpc 将这些 Enum 解析为字符串?

【问题讨论】:

    标签: node.js grpc grpc-node


    【解决方案1】:

    如果您使用@grpc/proto-loader 库,您可以将选项enums 设置为值String(不是字符串“String”,构造函数String)。然后所有的枚举值都将由它们的名称字符串表示。

    【讨论】:

    • 能否请您详细说明或提供一些示例代码来说明如何做到这一点?
    • @Sumit - 请考虑我在下面的回答作为一个可能的例子。
    【解决方案2】:

    在我们的项目中,我们使用enum 来帮助我们通过消除人为错误来确保有限可能性集的完整性。当我们有这么方便的协议缓冲区enum 时,为什么我们需要记住字符串值是什么?因此,我们使用.proto 作为事实来源;这是我们的规则。

    为此,请按照这些为 ES6+ 代码编写的步骤操作。

    1. .proto 文件中定义您的gRPC/Protobuf enum
    // life.proto
    syntax = 'proto3';
    package life;
    
    enum Choices
    {
      EAT = 0;
      DRINK = 1;
      SLEEP = 2;
      CODE = 3;
      SKI = 4;
    }
    
    1. 安装@grpc/proto-loader@grpc/grpc-js
    $ npm i -s @grpc/proto-loader @grpc/grpc-js
    
    1. 导入支付账单的模块,可以这么说。将.proto 文件直接加载到内存中(不要编译)。
    // myNodeApp.js
    import * as grpc from '@grpc/grpc-js'
    import * as protoLoader from '@grpc/proto-loader'
    import path from 'path'
    
    // these options help make definitions usable in our code
    const protoOptions = {
      keepCase: true,
      longs: String,
      enums: String,
      defaults: true,
      oneofs: true
    }
    
    // this allows us to prepare the path to the current dir
    const dir = path.dirname(new URL(import.meta.url).pathname)
    // this loads the .proto file
    const lifeDef = protoLoader.loadSync(path.join(dir, 'life.proto'), protoOptions)
    // this loads the package 'life' from the .proto file
    const life = grpc.loadPackageDefinition(lifeDef).life
    
    1. 查看enum Choices 定义(在同一文件中)。
    // myNodeApp.js (cont'd)
    console.log(life.Choices)
    
    /* stdout */
    {
      format: 'Protocol Buffer 3 EnumDescriptorProto',
      type: {
        value: [ [Object], [Object], [Object], [Object], [Object] ],
        name: 'Choices',
        options: null
      },
      fileDescriptorProtos: [
        <Buffer 0a ... 328 more bytes>
      ]
    }
    

    ...深入了解...

    console.log(life.Choices.value)
    
    /* stdout */
    {
      value: [
        { name: 'EAT', number: 0, options: null },
        { name: 'DRINK', number: 1, options: null },
        { name: 'SLEEP', number: 2, options: null },
        { name: 'CODE', number: 3, options: null },
        { name: 'SKI', number: 4, options: null }
      ],
      name: 'Choices',
      options: null
    }
    
    
    1. 使用enum
    // myNodeApp.js
    const myDay = { // plain JSON (or define a gRPC message, same same)
      dawn: life.Choices.type.value[1].name,
      morning: life.Choices.type.value[0].name,
      afternoon: life.Choices.type.value[4].name,
      evening: life.Choices.type.value[3].name,
      night: life.Choices.type.value[2].name
    }
    

    您可以编写访问器或实用程序函数来管理键查找(通过传递导入的 grpc enum 和索引),如下所示:

    export const getEnumByName = function (protoEnum, needle) {
      return protoEnum.type.value.find(p => {
        return p.name === needle
      })
    }
    
    export const getEnumByNum = function (protoEnum, needle) {
      return protoEnum.type.value.filter(p => {
        return p.number = needle
      })
    }
    
    export const getEnumKeys = function (protoEnum, key = 'name') {
      return protoEnum.type.value.map(p => {
        return p[key]
      })
    }
    

    反转并为 Message 赋值是其他答案中已经涵盖的内容,只需将枚举字段设置为字符串值,您猜对了,使用代表枚举名称的字符串,您可以访问它使用上面的代码。

    这与我们的做法一致。简洁明了,只是有点晦涩难懂,直到有一天你看到“引擎盖下”。

    详细了解@grpc/proto-loader@grpc/grpc-js。希望这可以帮助野外的人。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-02
      • 1970-01-01
      相关资源
      最近更新 更多