适用于Swift iOS App的GRPC BFF
gRPC移动BFF
本教程重点介绍后端前端(BFF)设计模式如何表示移动应用程序开发人员“永远的最佳朋友”,尤其是不同的技术如何帮助实现最佳BFF,从而实现移动应用程序的最佳反应性和响应性 。
一般而言,BFF的目标是简化客户端应用程序的开发时间,以使“服务API”调用解耦,从而有可能减少调用次数,并最终在不同的客户端实现中共享一些逻辑,从而优化常规网络和数据转换,同时增加共享的数据连接,分页,缓存,同步,流式传输等,并最终执行安全性和其他策略。
Internet上已经有很多教程介绍了这种现在非常普遍的设计模式。 在这里,我们没有谈论多通道,微服务,api网关,服务网格,也没有使用任何其他现代的“服务器”术语,我们只是说BFF是移动应用程序与每个移动设备“服务API”之间的“中间件”。应用需要在云端或内部调用。
本教程更具体地侧重于BFF模式如何帮助简化对这些服务API接口的访问,尤其是采用gRPC协议在很大程度上确实有助于减小数据大小,优化网络以及实现和实施一系列协议。共享的基础结构功能。
当然,与其他许多领域一样,这里没有银弹。 其他接口(例如GraphQL)可以在某些情况下提供其他好处,而特定的移动技术(例如iOS上的URLSession后台下载任务)可以在特定移动环境下(例如有限的多任务处理)对网络优化提供非常强大的控制
样本问题:必须全部抓住!
在本教程中,我们将创建一个移动应用程序和一个BFF服务器,以实际演示该设计模式的优势。
我们将创建一个Pokédex移动应用程序,该应用程序将使用公开可用的http://pokeapi.co/ REST API,允许用户按名称或类型搜索Pokemons,并将为找到的每个Pokemon显示以下信息:
- 名字
- 图片
- 所有类型
- 身高和体重
- 他住在哪儿
- 物种栖息地的全文描述(风味文字)
为了获取所有这些数据,将使用以下后端REST API:
- / pokemon :获取特定口袋妖怪名称的基本口袋妖怪数据
- / pokemon-species :获取特定口袋妖怪的栖息地信息
- / type :获取特定类型名称的所有宠物小精灵的列表
为什么我们需要BFF?
等一下 这些Pokemon API只是简单的REST API,我可以轻松地从移动应用程序本身直接调用它们。 为什么我需要gRPC,更重要的是为什么要使用BFF?
那就对了。 这些API可以直接由移动应用本身使用,但让我们在下面的图片中看到这些简单方法的缺点。
首先,我们可以看到,即使这个超级简单的应用也需要协调来自三个不同网络API调用的数据。
基本上,要搜索特定类型的所有宠物小精灵,我们需要先调用/ type Rest API以获取口袋妖怪名称或ID的列表,然后对于此列表中的任何单个口袋妖怪,我们都需要调用/ pokemon Rest API以获取基本信息例如名称,类型,高度和宽度,还可以调用/ pokemon-species Rest API获取栖息地信息。
除了需要“协调”对不同的Rest API的调用之外,另一个需要重点关注的事情是,所有这些神奇宝贝Rest API都返回了我们渲染应用程序用户界面实际所需的更多数据。
实际上,在此示例iOS移动应用程序中,我们将使用非常经典的UICollectionView界面,并且仅需要在集合单元中显示上面介绍的口袋妖怪信息(名称,图像,类型等)。 这些神奇宝贝Rest API会通过网络(可能在蜂窝网络上)传输许多我们实际上在简单的App中根本不需要的其他数据。
Node.js中的经典BFF
现在是否更清楚BFF服务器在简化不同后端API调用的编排方面的角色,而且还提供了过滤和仅在网络上仅将App严格需要的数据传输到Mobile App的好处。
今天,有许多不同的技术可用于实现此BFF服务器。 本机iOS移动应用程序开发人员现在甚至可以在Linux和Kitura或Vapor等服务器框架上使用Swift来轻松实现这些BFF。 这些Swift Server框架的即将发布的新版本中采用Apple开源Swift Nio库将很快提供更多的效率和可扩展性(请参阅https://medium.com/@JMangia/apple-swiftnio-netty-vert-x -grpc-and-service-mesh-ab5840c1b71c)。
Node.js也是实现这种BFF服务器的最常用平台之一,因为它提供了极大的简便性,并且由于采用了事件循环体系结构及其单线程异步I / O支持而带来了很多好处。
使用Node.js和Javascript框架(如Express.js)非常容易实现这种BFF服务器。 在与本教程相关的Github存储库中,您将在BFF / Rest文件夹下找到此REST BFF服务器的Node.js简单实现。
正如我们之前在本教程介绍中所讨论的,BFF也是实现基础结构功能(例如身份验证,授权,缓存和其他通用功能)的地方。 在我们的BFF Node.js实现中,特别是使用Javascript Node-Cache包实现了本地内存中的缓存,以便本地存储从后端PokeApi返回的数据并减少流向后端的网络流量。
简化的API
我们已经说过,BFF还可以为Mobile App提供简化的API接口。 在我们的特定情况下,我们的BFF公开了唯一且通用的/ Search API,移动应用程序会使用它来搜索单个特定的宠物小精灵名称或从特定的类型名称中搜索所有的宠物小精灵。
下图说明了此单个客户端API的伪代码实现,尤其是它基本上如何协调对上文已介绍的不同PokeApi调用的调用。
有了这样的通用/ Search API,我们的移动应用程序的UI可以大大简化,从而基本上提供了单一用户体验,可以同时搜索每种神奇宝贝类型或每种神奇宝贝名称,而不必要求用户点击其他任何按钮在屏幕上,而是在BFF的帮助下拥有移动应用程序本身,butter理解了用户仅搜索名称的简单通用意图。
无论如何,BFF通过此优化和简化的/ Search API引入的新抽象层在最终用户体验上产生了以下非常关键的问题:移动应用程序现在需要等待BFF / Search的输出的执行和网络传输API,然后获取重新加载和呈现UICollecionView所需的所有数据。
基本上,在开始向用户显示新数据之前,移动应用需要等待BFF从缓存或通过调用PokeApi后端Rest API收集满足搜索请求所需的所有数据。
Node.js中的gRPC BFF
最后,我们将在这里看到gRPC协议的采用可以为我们的移动应用程序带来响应和反应方面的好处。
本教程的目的不是全面介绍gRPC网络协议和Protocol Buffer数据协议。 Internet上已经存在很多很棒的教程。
我们将在这里简单地关注以下优点:仅使用支持优化HTTP的gRPC服务接口,现代HTTP / 2网络协议的“透明”采用可以为我们的BFF实现以及移动应用程序和BFF之间的通信提供优势。 / 2流网络。
下图基本上预见了使用gRPC协议将BFF模式的这种新功能直接传输到客户端Collection查看从缓存或从Rest API调用到PokeApi后端收集的数据,并立即连续不断地向用户提供反馈,而无需等待全部时间执行整个搜索操作。
Protobuf gRPC接口
这基本上是为我们的BFF搜索服务定义的ProtoBuf / GRPC接口。
如您所见, searchPokemon gRPC API(第24行)被定义为服务器到客户端的流gRPC接口,该接口将流化在同一protobuf文件中描述的Pokemon类型的对象(第5-15行)。
Swift gRPC客户端代码
一旦我们有了描述原始数据结构和BFF API的gRPC服务接口的protobuf文件,我们就可以生成相应的Swift文件,并将其与整个Swift gRPC软件包堆栈一起合并到我们的iOS Swift移动应用程序项目中。
一旦安装了gRPC运行时以及Swift ProtoBuf和GRPC插件(遵循Swift GRPC github网站上的说明),您就可以轻松地执行以下命令行来生成这些Swift输出文件,以将其包含在XCode项目中:
protoc \
--swift_out =。 \
--swiftgrpc_out =。
下面的Swift PokemonDataSource类只是包装对protoc / grpc自动生成的swift文件的访问,以便简化从实现UICollectionView的视图控制器对gRPC接口的访问。
通过这种方式,Swift视图控制器类将仅调用datasource.searchNewPokemon gRPC包装器方法,并且将为通过gRPC — HTTP / 2网络接口从BFF服务器流式传输的任何pokemon数据调用从视图控制器传递的完成块 。
Node.js gRPC BFF代码
Swift gRPC堆栈当前还支持服务器端代码生成,但是为了本示例教程的完整性,我选择再次使用Node和Javascript编写以下gRPC BFF实现的代码:
完整的源代码
GitHub存储库提供了针对Client和BFF项目的本教程的完整源代码:
JacopoMangiavacchi / PokemonBot
PokemonBot – Swift GRPC Streaming BFF测试 github.com