在本章中,我们将配置一个现代的、可持续的构建过程,为在Node.js上使用GRPC奠定基础。
在第2部分中,我们将在这些学习的基础上,以打印脚本的形式实现GRPC服务器。最后,在第3部分中,我们将以关于代码组织、测试、部署、进一步改善开发人员体验等主题的有用提示和技巧来结束。
让我们从创建一个新项目开始(您可以选择使用git init)。
在我们开始讨论工具之前,让我们先定义我们的“公共”消息以及我们的服务,将其恰当地命名为HelloService。
既然我们已经定义了我们的Protos,那么让我们安装和配置buf,看看我们可以改进…的哪些方面。
如果您使用的是MacOS,则可以使用BREW。有关其他安装选项,请参考官方指南。
根据官方指南,我们将首先创建我们的buf配置(buf.yaml)。出于本教程的目的,我们将使用最严格的皮棉设置。
$buf check lint com/language/language.proto:3:1:包名";com.language";应以格式正确的版本作为后缀,例如";com.language.v1";。Com/language/language.proto:10:5:枚举值名称";en";应以";code_";为前缀。Com/language/language.proto:10:5:Enum零值名称";en";应以";_UnSpecified";为后缀。Services/hello/hello_service.proto:5:1:Package名称";services.Hello";应该以格式正确的版本作为后缀,例如";services.hello.v1";。
在proto/com/language/language.proto中,我们将按照建议更新Language.Code Enum值,该包现在需要包含一个版本(V1)。
在proto/services/Hello_service.proto中,我们将更新对Language.Code的引用以包括v1,包现在还需要包括一个版本(V1)。
运行buf check lint再次失败,这一次是因为我们被告知目录结构必须与包名称间距匹配。
$buf check lint com/language/language.proto:3:1:带有包";com.language.v1";的文件必须位于相对于根目录的";com/language/v1";目录中,但位于";com/language";目录中。Services/Hello/Hello_service.proto:5:1:带有Package";services.hello.v1";的文件必须位于相对于根目录的";services/Hello/v1";目录中,但位于";services/Hello&34;目录中。
我们需要做的就是将Protos移到它们各自的.VERSION目录中,在我们的例子中是v1。要验证,请执行以下操作:
FileDescriptorSets是在整个Protobuf生态系统中使用的原语,用于表示已编译的Protobuf模式。它们也是proac生产的主要产品。
你可能也知道,使用proc和proc插件可能会很麻烦,有些人甚至会说很痛苦。
BUF的目标是通过它所谓的图像来缓解这些痛苦。Image本质上是Buf对FileDescriptorSets的自定义扩展。因为它是一个扩展,所以Images是FileDescriptorSets,而FileDescriptorSets是Images。
当然,您可以从各种格式中进行选择,但出于本教程的目的,我们将坚持使用json。
现在我们已经成功构建了一个映像,我们可以将其用作基线,以确保任何新的更改都不会破坏向后兼容性。
让我们看看,如果我们试图在其中一条消息中引入一个突破性的变化,会发生什么。例如,我们可以将LANGUAGE_CODE从位置2更改为位置3。
$buf支票中断--已删除消息";GreetRequest";上名称为";Language_services/hello/v1/hello_service.proto:11:1:Previously";的Image.json语言当前字段";,但不保留名称";Language_Code";。已删除消息";问候语";上名为";语言_代码";的services/hello/v1/hello_service.proto:11:1:Previously显示字段";2";,但不保留编号";2";。
这在CI/CD上下文中可能特别有用。例如,您可以将“基线”图像人工产物存储在某个地方,并拒绝任何未通过中断更改检测的潜在更改,从而只允许在没有引入中断更改的情况下更新“基线”图像。
虽然当然可以使用@grpc/proto-loader库将.proto文件直接加载到运行时中,但对于那些想要使用TypeScrip的人来说,这实际上意味着不再输入任何内容。
BUF具有生成功能,这降低了使用和配置proc+插件的复杂性,并进一步简化了流程。让我们试一试吧!
⚠️注意:下面假设您已经安装了Protoc(3.12.3版或更高版本)。
如果愿意,您可以更改或完全省略opt,但出于本教程的目的,我们将使用推荐的选项。有关更多详细信息,请参阅https://developers.google.com/protocol-buffers/docs/reference/javascript-generated#compiler-options。
$TREE BUILD/NodeJS Build/NodeJS├──COM│└──Language│└──v1│└──Language_pb.js└──服务└──HELLO└──v1└──HELLO_SERVICE_Pb.js 6个目录,2个文件。
为此,我们需要安装GRPC-Tools来获取GRPC_TOOLS_NODE_PROTOC插件。
Out选项与js插件相同-我们希望将JavaScript和GRPC生成的模块放在同一位置。
如果愿意,您可以更改或完全省略该选项,但出于本教程的目的,我们将使用grpc_js选项,该选项指示插件生成使用@grpc/grpc-js的代码(而不是即将废弃的GRPC)。有关更多详细信息,请参阅GRPC-Tools。
再次运行buf Generate之后,我们将看到new_grpc_pb.js文件。
$TREE BUILD/NodeJS Build/NodeJS├──COM│└──Language│└──v1│├──Language_grpc_pb.js│└──Language_pb.js└──服务└──HELLO└──v1├──HELLO_SERVICE_GRPC_pb.js└──HELLO_SERVICE_pb.js 6个目录,4个文件。
首先,我们安装所需的插件(proc-gen-ts)。有趣的是,这是我们到目前为止使用的唯一遵循协议命名约定的插件。
默认情况下,buf将在$PATH上查找proc-gen-name(如下所示,名称为ts),因此我们不需要为该插件使用路径选项。
Out选项与GRPC和js插件的选项相同--我们需要将所有类型的脚本定义与它们的JavaScript对应项放在同一位置。
与GRPC_TOOLS_NODE_PROTEC插件一样,如果愿意,您可以更改或完全省略该选项。出于本教程的目的,我们将使用grpc_js选项指示插件生成使用@grpc/grpc-js的代码(与即将废弃的GRPC相对)。有关详细信息,请参阅GRPC_TOOLS_NODE_PRORC_TS。
让我们做最后一次BUF建造吧。现在我们应该看到打字稿定义。
$TREE BUILD/NodeJS Build/NodeJS├──COM│└──Language│└──v1│├──Language_grpc_pb.js│├──Language_pb.d.ts│└──Language_pb.js└──服务└──Hello└──v1├──HELLO_SERVICE_GRPC_pb.d.ts├──HELLO_SERVICE_GRPC_pb.js├──HELLO_SERVICE_pb.d.ts└──HELLO_SERVICE_pb.js 6个目录,7个文件。
恭喜你!您已经完成了第1部分,您可以在即将到来的服务器和客户端实现中使用这些模块。
在第2部分中,我们将详细介绍我们构建的内容,并用TypeScript实现一个Node.js GRPC服务器。