使用WunderGraph构建前后端BFF的7个技巧

前端后端 (BFF) 是一种专门的服务器端 API,充当前端(客户端)应用程序和各种下游 API 之间的中介,在将数据传递到前端之前根​​据需要聚合和转换数据。

这里有一些关于前端后端的陷阱、提示和技巧以及一般开发人员建议:

1. 了解您*不是*构建 API 网关。
我发现,为了安全起见,最终构建一个 API 网关而不是一个合适的 BFF 是非常容易的。
API 网关在概念上很简单,而且相当有吸引力。将基于 HTTP 的抽象放在多个下游服务前面,使客户端在这些下游服务发生变化时免受变化 — 很简单,对吗?不完全是。

随着您的应用程序的发展,纯粹的 API 网关方法不可避免地会变成一种适用于多个客户端和体验的包罗万象的整体 API,并且任何新功能(在任何受支持的客户端上)都必须确保与此 API 的兼容性。

前端后端与 API 网关的不同之处在于,它是专门为一种客户端/用户体验而构建的,每种客户端/用户体验都有一个 BFF。

您的产品是否包含 React 桌面应用程序、Android/iOS 应用程序和 Xbox/PlayStation 应用程序?使用 BFF 模式,就不会让三个客户端与一个承担多项职责的 API 网关同时进行通信,而是下面:

  • 为每个客户团队专门构建一个“后端”,由每个客户团队拥有。
  • 每个网关都比 API 网关更小、更简单,并且更易于维护,因为这种模式促进了固有的关注点分离。
  • 每个都完全按照其特定客户的 UI 需求进行操作,而不做其他事情。

这个想法很简单:由于您同时拥有客户端和“服务器”组件,因此您始终可以创建完美的“后端”,并使用一个函数,该函数在调用时会以完全正确的格式返回所需的数据。这些客户 + BFF 团队之一甚至不必担心下游资源如何工作。

2.考虑使用BFF框架。
构建生产就绪的 BFF 需要您重新发明一堆部件——请求路由和分派、API 聚合和编排、数据转换/格式化、中间件、缓存、日志记录和错误处理、安全性。

对于如何实际构建和整合所有这些层,社区中没有既定的规范,甚至没有达成共识。

出于这个原因,我使用 WunderGraph——一个免费的开源(Apache 2.0 许可证)后端换前端框架,可以使用 Docker 进行部署,这让我省去了编写和粘合样板文件的麻烦。

那么 WunderGraph 非常适合:

  1. TypeScript(并理解为什么类型安全是必要的),
  2. 构建数据密集型应用程序,
  3. 需要汇集来自 SaaS 提供商的数十个微服务、数据库和身份验证/支付 API

它允许我将所有这些依赖项(无论它们是使用不同的技术构建、使用不同的身份验证/授权工作流程还是以不同的格式返回数据)组合成一个统一、安全、可扩展的 API。然后,我可以编写 GraphQL 或 TypeScript 操作来聚合、处理、验证或以其他方式获取我需要的数据,通过 RPC 作为 JSON 提供服务。

我不需要手动组合和编排所有这些依赖项。我只是以声明方式将它们定义为配置即代码,让 WunderGraph SDK 为我生成统一的 API,然后在前端和后端进行类型安全访问(支持所有主要前端框架,如 React、NextJS、Remix、 Astro、Svelte、Expo、Vue 等)。

除了 TypeScript 代码之外,您永远不需要使用任何东西,并且您将拥有内置的缓存、测试/模拟、安全性、分析、监控和跟踪来启动。

3. 缓存、身份验证和日志记录在 BFF 层中运行良好。
BFF 层是减轻客户端和后端服务负担的完美场所,使他们的代码更加简单。将缓存、身份验证和规范化错误处理等辅助问题引入 BFF 通常是一个好主意。

缓存
BFF 知道客户端需要的确切聚合,因此我们可以在 BFF 前面放置一个反向代理,将所需的视图特定响应的副本存储在其缓存中,并将其提供给请求相同聚合的后续客户端。我们还可以提前生成成本高昂的数据模型/聚合。

WunderGraph 会自动对所有 BFF 操作进行哈希处理,将它们转换为仅响应客户端对有效哈希值的请求的持久查询。WunderGraph BFF 服务器为每个响应生成一个实体标签 (ETag),将其与每个后续请求的服务器上的 ETag 进行比较,如果它们相同,则表明没有任何更改,并且客户端的缓存版本仍然是有效的。这在客户端上开启了非常快速的“重新验证时失效”策略,无需手动设置到期时间,并仔细计算它以等于给定聚合所需的最新内容。

授权
身份验证通常涉及与外部身份提供商、用户目录或单点登录 (SSO) 系统集成。这是一个非常适合 BFF 层的功能,其原因不仅仅是简化前端/后端代码库:

  1. 每个客户端(或更准确地说,用户体验)可能有独特的身份验证要求。通过在 BFF 中实现身份验证,您可以定制身份验证逻辑以满足每个客户端的特定需求/标准。这允许进行细粒度、上下文感知的身份验证。
  2. 在 BFF 中实现身份验证比在上游的另一个 Nginx 服务器上实现更有意义,您必须独立测试、部署和维护。
  3. 另外,在 BFF 中进行身份验证只是另一层安全性,因为 BFF 本质上对客户端隐藏了所有后端架构/实现。
  4. 如果您的应用程序需要支持使用多个凭据进行身份验证(经典用户名/密码、外部 OAuth 提供商(如 Google/GitHub、2FA/MFA 等)),BFF 可以集成多个身份提供商,将其映射到客户端的统一接口。(使用 WunderGraph,您可以添加身份验证提供程序,就像使用 NPM 添加软件包一样 - 请在此处查看更多信息。)
  5. BFF 还可以实现基于用户角色的细粒度访问控制,通常称为基于角色的访问控制 (RBAC)。由于授权逻辑驻留在集中位置,因此在 BFF 中实施的 RBAC 简化了访问控制规则的维护和更新。

记录
BFF 本质上充当请求的中介者,考虑到它处理的入站和出站流量的巨大数量,使其成为实施日志记录的绝佳场所。无论哪个客户端发出请求,您都将拥有集中式日志记录。
另外,由于 BFF 处理的大部分数据都是聚合的,因此此级别的日志记录实际上可以暴露与性能相关的问题,从而帮助前端和后端开发人员。
但不仅仅如此。登录 BFF 层的真正附加值是上下文。BFF 拥有有关每个请求的宝贵上下文信息。他们可以提取重要的详细信息,例如用户的身份、使用的前端应用程序的类型、访问的 API 端点以及发送的参数。实际上,您可以使用这个关键上下文来丰富日志,从而使调试变得更加容易。
最后,由于 BFF 充当前端和后端服务之间的安全屏障,因此此处记录还允许检测传入请求中的潜在恶意模式。

4. 规范错误
BFF 是服务器层上的请求聚合器,将多个请求发送到一个或多个下游服务,异步收集所有响应,在准备就绪后将它们拼接在一起,然后将它们发送回客户端应用程序。

但这些下游服务可能会以截然不同的方式失败,并且它们返回的错误也可能截然不同。有些可能会抛出泛型HTTP 500(您可能不希望这样),有些会抛出HTTP 200 OK但在正文中包含错误数据,有些甚至根本不返回 JSON,而是返回 XML/HTML。

BFF 本质上是前端和域服务之间的转换层,能够很好地转换和映射这些不同的错误/错误消息,而且最重要的是,使用标准化的错误状态来执行此操作。

在传统的 REST API 中,验证失败的请求会让您返回 4xx 或 5xx HTTP 状态代码,但如果您的域服务之一是 GraphQL API,该怎么办?
GraphQL API总是会给你一个 200 状态代码,响应负载内容包含特定的错误信息。如果您将此责任传递给客户端,则所需的错误处理逻辑(带有适当的 UI/UX 反馈)将使其变得臃肿且难以维护。


  "data" :  { 
   
"updateUserProfile" :  null
     } , 
   
"errors" :  [ 
        { 
       
"message" :  "字段'updateUserProfile'缺少必需的参数:输入"
       
"locations" :  [ 
        { 
       
"line" :  2 , 
       
"column " :  3 
        } 
      ] , 
     
"扩展名" :  { 
       
"代码" :  "BAD_USER_INPUT" 
      } 
    } 
  ] 
}


这就是 BFF 发挥作用的地方。BFF 可以负责处理来自后端的 GraphQL 响应,然后将任何潜在错误规范化为客户端应用程序可以明确解释和显示的一致格式。


  “status” : “error” ,
  “code” : “BAD_USER_INPUT” ,
  “message” : “字段“updateUserProfile”缺少必需参数:输入” 
}


您现在可以将其作为 HTTP 400 错误请求返回,其中包含有关格式错误或缺少所需数据的特定信息。BFF 充当中介,规范下游错误响应,为其客户端提供必要的信息以了解其请求的结果,并以标准化方式处理错误。

您可以用它做很多很多事情,例如添加规范的超时时间。或者在必要时添加自定义标头。

5. 集成测试
BFF 在将最终响应传递给客户端之前聚合和编排来自多个下游服务的数据,因此很明显,这将是根据商定的 API 规范以及客户端所需的格式测试和验证数据的好地方。

但它也是测试使用真实后端数据可能难以实现的特定用例的好地方。例如,模拟错误响应、边缘情况、资源受限或降级的服务场景。仅仅依靠真实的后端数据进行测试可能会导致瓶颈和不一致,因此模拟 BFF 中的数据可以让开发人员继续进行测试,即使实际的后端系统尚未完全开发或可访问。

但模拟数据不仅仅可以用于测试。这还意味着您将有更快的上市时间,因为前端团队无需等待后端团队提供他们所需的更新 API。他们可以在开发过程中嘲笑响应。