构建更聪明的,不是更难:用build time graphql简化后端工作流程
#javascript #网络开发人员 #编程 #graphql

Fancy Image of your Architecture if you use Wundergraph

使用构建时间GraphQl固定后端for-for-for-for-fortends模式

BFF模式优化了特定客户端接口的后端。使用GraphQl来修复其一些缺点,但是我们可以做得更好吗?让我们与Wundergraph一起找出答案。

当您拥有多个客户端平台时,first described by Sam Newman和首次在SoundCloud使用的后端模式(BFF)模式是一个有效的解决方案 - Web浏览器,移动应用程序,游戏机,游戏机,IoT设备,IoT设备 - - IOT设备 - - 每个都有对数据,缓存,AUTH等独特要求的要求。

BFF是一个自定义接口(由前端团队维护),是为每个客户端平台的需求而构建的,就客户端而言,它是唯一的后端。它位于客户端和基础数据源/微服务之间,使它们脱钩,并使每个客户团队完全控制他们如何消耗,合并和按摩来自下游API依赖关系的数据,并处理其错误。

但是,BFF模式与工程中的其他任何内容一样,具有折衷和弊端。但是,事实证明,GraphQl非常擅长解决这些缺陷,并且GraphQL驱动的BFF层效果很好。但是,GraphQl带来了它自己的一系列问题!

在这里听起来像是一个破裂的记录。我们如何打破周期?让我们谈论它,看看一种免费的开源技术 - WunderGraph-可以帮助我们。

for-for-forrontendsâ€graphql

bff可以像简单的整体中一样维护和保护一个单个入口点的奢侈,同时仍在内部使用微服务。这给出了两全其美的最好,但是这种敏捷性是有代价的。让我们看看其中一些问题,以及GraphQl如何使它们无效:

1。 bffs作为一个聚合层,但是您仍然需要多个请求才能获取所需的数据,这与微服务的数量线性缩放/您拥有的API/数据依赖性。多个网络啤酒花增加了延迟。

GraphQl在最小化多个往返方面非常有效,因为它本来可以使客户在单个查询中请求多个资源和关系。

2。过度取回和取消效果可能仍然是问题,因为固有的固有方式以及您可能依靠遗产或您不拥有的架构的第三方API这一事实的结合。

图像来源:https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

在RESTFUL API中,确定返回数据的结构和粒度的服务器,这可能导致数据比客户端实际需要更多的数据。

GraphQl将该责任转移到客户端,他们可以在单个查询中准确指定所需的数据。

图像来源:https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

您的下游微服务/API是否使用GraphQl本身对客户端/BFF交互都不重要。您将不需要重写任何收益。

3。文档将是一个正在进行的琐事。对于特定客户而言,BFF是专门构建的,因此每个BFF都需要创建详细的随附的API文档(带有有效载荷/响应规格),并保持最新状态日期。如果使用休息,端点名称和http动词只会随着应用程序及其复杂性而增长,使其难以记录,因此很难为新员工登上新员工。

GraphQl本质上是声明性和自我记载。一个端点,所有可用的数据,关系和API都可以由客户团队(通过GraphiQL interface或Just Introspection)探索和消费,而无需与后端团队来回往返。

但是,GraphQl不是银弹。

毫无疑问,采用GraphQl汇总了一些BFF问题,但是GraphQl的采用并不是要轻轻地采取一些措施。它不仅是另一个UI库,还可以添加到您的技术堆栈中,而且与工程学的任何内容一样,它具有越来越多的痛苦,权衡和与之相关的复杂性。

1。 GraphQl具有陡峭的学习曲线。理解其概念 - 模式,类型,查询,突变和订阅 - 需要大量的时间投资,编写良好的解析器功能需要很好地理解基础数据模型以及如何从不同来源(数据库,API或服务)检索和操纵数据。服务器端数据合并是一个整洁的想法,但这使您的GraphQL实现仅与您的解析器一样好,并且涉及大量的样板,可以使实现更详细和错误。

2。 GraphQl没有内置的缓存。 graphQl的单端点格式带给表的简单性也可以在某些情况下变成瓶颈 - rest APIS多个端点允许它们允许它们使用HTTP缓存来避免重新加载资源,但是使用GraphQl,您仅对所有内容都使用一个通用端点,并且必须依靠外部库(如Apollo)进行缓存。

3。 GraphQl客户端的捆绑尺寸可能非常沉重,您必须运送。在某些用例中,这可能并不重要(例如,如果您仅构建内部应用程序),但是它可以并且确实会影响应用程序的负载时间和性能,尤其是在低频带宽度或缓慢网络连接的情况下是一个问题。

4。如果您不小心,则性能可能是一个令人担忧的问题。在GraphQL中执行速率限制要比休息更加困难,而且单个查询过于复杂,太嵌套,获取了太多数据,可以使您的整个后端爬行。甚至偶然!为了减轻这种情况,您将需要算法来计算查询成本,然后才能获取所有数据,这是其他开发人员的工作。 (供参考,this is how GitHub’s GraphQL API does it

5。 GraphQl没有内置的方式来确保安全。息息相关的广泛流行和身份验证方法使其成为安全的更好选择原因比GraphQl。虽然REST具有内置的HTTP身份验证方法,但使用GraphQL,用户必须在业务层中找出自己的安全方法,无论是身份验证还是授权。同样,库可以提供帮助,但这只是为您的构建增加了更多的复杂性。

引入WunderGraph。

WunderGraph是一个免费的开源(Apache 2.0许可证)框架,用于构建后端for-Frontends。

GitHub - wundergraph/wundergraph: WunderGraph is a Backend for Frontend Framework to optimize…

_WunderGraph is a Backend for Frontend Framework to optimize frontend, fullstack and backend developer workflows through…_github.com

使用wundergraph,您定义了许多异质数据依赖项 - 内部微服务,数据库以及第三方API,为config-as as-as-as-assode,并且每个都会内省将它们汇总并将其抽象成namespaced虚拟图。

在这里,您可能会使用WunderGraph构建的系统。

让我们深入研究。首先,您必须将API和服务命名为数据依赖项,就像您将项目依赖关系添加到package.json文件一样。

./. Wundergraph/wundergraph.config.ts

// Data dependency #1 - Internal database  
const db = introspect.postgresql({  
 apiNamespace: "db",  
 databaseURL: "postgresql://myusername:mypassword@localhost:5432/postgres",  
});  

// Data dependency #2 - Third party API  
const countries = introspect.graphql({  
 apiNamespace: "countries",  
 url: "https://countries.trevorblades.com/",  
});  

// Add both to dependency array  
configureWunderGraphApplication({  
 apis: [db, countries],  
});

您可以编写GraphQl操作(查询,突变,订阅),以获取所需的数据从该合并虚拟图。

././.wundergraph/operations/countrybyid.graphql

query CountryByID($ID: ID!){  
 country: countries_country(code: $ID) {  
 name  
 capital  
 }  
}

./. Wundergraph/operations/users.graphql

query Users($limit: Int!){  
 users: db_findManyusers(take: $limit) {  
 username  
 email  
 }  
}

- WunderGraph将自动生成端点,您可以通过JSON-RPC进行卷曲以执行这些查询并返回所需的数据。

> $ curl http://localhost:9991/operations/CountryByID?ID=NZ  
> {"data":{"country":{"name":"New Zealand","capital":"Wellington"}}}
> $ curl http://localhost:9991/operations/Users?limit=5  
>{"data":{"users":[{"username":"user1","email":"user1@example.com"},{"username":"user2","email":"user2@example.com"},{"username":"user3","email":"user3@example.com"},{"username":"user4","email":"user4@example.com"},{"username":"user5","email":"user5@example.com"}]}}

如果您使用数据获取库(例如SWRTanstack Query)或基于React的框架(NextJS,Remix等),您会从WunderGraph中获得更多信息,因为它会自动生成精益,performant,performant,performant,performant,sustompulty typescript每次定义操作时,客户端都为您提供,并配有用于查询和突变数据的完全类型的安全挂钩,无论您需要在何处,您都可以在前端使用。

./pages/index.tsx

// Import data fetching hook from WunderGraph-generated client  
import { useQuery } from "../components/generated/nextjs";  

const Home: NextPage = () => {  
 // Data dependency #1 - Internal Database  
 const { data: usersData } = useQuery({  
     operationName: "Users",  
     input: {  
     limit: 5,  
     },  
 });  

 // Data dependency #2 - Third-party API  
 const { data: countryData } = useQuery({  
     operationName: "CountryByID",  
     input: {  
     ID: "NZ",  
     },  
 });  

//...  
}

现在,您可以根据需要使用usersDatacountryData。将其渲染成卡片,清单,将其传递给道具,狂野。

但是,WunderGraph如何解决GraphQl的问题?

很容易 - wundergraph将GraphQl完全从运行时

是的,您确实编写了GraphQl操作,以从多个数据源收集和汇总所需的数据,但这就是这样。您必须编写解析器,或者担心使它们在数据获取方面有效。您参与GraphQL仅到编写查询,并且仅在开发过程中。没有公共GraphQl端点暴露,也没有在客户端上运送任何重的GraphQL客户端。

如果这不会立即点击您,请不要担心。我保证这很快就会有意义。让我们详细查看此过程。

仅在本地开发过程中GraphQL?

每当您编写GraphQl查询,突变或订阅并命中保存时,查询就不会如原样保存。 相反,它是哈希并保存在服务器上的,只能通过呼叫哈希名称来访问客户端(当然与输入变量一起)。

这就是所谓的持续查询。您的wundergraph bff服务器具有已知的哈希列表 - 与您定义的持续疑问一样多 - 并且将唯一响应客户的有效哈希的请求,将其作为JSON服务。在RPC上,每个操作都有唯一的端点。 (并且WunderGraph生成了针对React框架和数据获取同一事物的库的Typesafe挂钩)

这是什么意思?两件事。

  1. 您解决了与浏览器网络请求进行反向工程相关的安全问题 - ,因为没有GraphQl API。
  2. 如果每个操作都有一个唯一的端点,则最终可以实现传统的休息式缓存!但这不是全部。 WunderGraph bff服务器为每个响应生成一个Entity Tag (ETag)-这是该响应内容的唯一标识符 - 如果客户端向同一端点提出后续请求,并且其ETAG与服务器上的当前ETAG,这意味着内容没有更改。然后,服务器可以使用HTTP 304响应,未修改,这意味着客户端的缓存版本仍然有效。这使得客户端陈旧的恢复策略迅速迅速。

您可以在开发时间内编写所有使用GraphQl的任意查询,但是它们在编译时进行了哈希并持续存在,并且仅在运行时出现为JSON RPC。在一口气中,您解决了GraphQl最常见的问题,创建了最佳世界的情况。 GraphQl的所有胜利,都没有缺点。

但是,过于复杂的查询的性能问题又如何呢?

WunderGraph在内部使用Prisma ORM,无论您的数据源如何,都为您编写的每个操作制作优化查询。您将不必担心手工滚动自己的SQL或GraphQl查询并对其进行消毒,以确保单个NAN-NAN-NAN-NAN-NAN-NAN-NANIN-NANIN-TRECH杀死您的下游服务,也不会导致DOS攻击。

>

从这往哪儿走?

您看到WunderGraph如何使Building Bffs变得更加容易,并且可以启动出色的Devex。它在引擎盖下使用Prisma,创建持续的查询并通过JSON-RPC提供服务,将GraphQl重新添加到本地开发中。

但是,您可以做得远不止在Wundergraph上 - 这是一个真正的BFF框架:

  • 它支持从正面到后的完全类型的防护开发。您编写的每个操作都会生成一个Typesafe客户端/挂钩,以从前端和you can even generate typesafe Mocks this way访问它!使用WunderGraph,您在后端和前端之间具有共享类型 - 在编写GraphQl查询时以及开发客户端时,都可以为您提供完整的IDE自动完成和推理。
  • 它可以将您写入的任何查询变成Live Query,甚至不需要Websockets-使WunderGraph非常适合构建与前端与无服务器平台一起部署的BFF的理想/em>使用Websocket。
  • 它还可以整合S3-compatible storage for file uploads,OIDC/non-oidc兼容验证提供商等等。
  • 如果您根本不想编写GraphQl,则可以编写自定义的TypeScript functions(基本上是异步解析器)来定义开发过程中的操作。您可以使用ZOD在其中执行JSON模式验证,并以任何方式汇总,处理和按摩数据,然后将其返回给客户端。打字稿操作的访问与GraphQL操作一样(JSON RPC端点或端口挂钩),并且完全在服务器上运行,并且永远不会暴露客户端。另外,您甚至可以在其中导入并使用现有的GraphQl操作。
  • 您可以通过Clerk/Auth.js/您自己的auth Solution,您自己的身份解决方案,可以在BFF层上烘烤理想情况下存在的跨切割问题 - 最重要的是auth--每个操作都可以意识到身份验证。

使用强大的内省,将API,数据库和微服务变成依赖项,就像NPM这样的软件包管理器一样,WunderGraph使BFF开发变得易于访问和快乐,而不会在端到端typefety上妥协。要了解更多信息,请查看他们的文档here和他们的Discord社区here