前言
GraphQL 在前端开发中越来越受欢迎,很多公司和团队都开始采用 GraphQL 构建他们的服务端 API。然而,GraphQL 的灵活性与强大性也带来了许多挑战和需要注意的地方。本文将介绍一些 GraphQL 服务器端 API 设计的规范和最佳实践,帮助您设计出更好的 GraphQL API。
设计规范
1. 定义好 Schema
GraphQL 的核心是 Schema。Schema 定义了数据类型、字段以及它们之间的关系。因此,在设计一个 GraphQL API 时,首要任务就是定义好 Schema。
Schema 可以被定义为一个字符串或写成一个类。如果你使用的是 Apollo Server,则可以考虑写成一个类。一个好的 Schema 应该包含以下几个部分:
- Query:查询数据(必需)
- Mutation:修改数据(可选)
- Subscription:实时数据更新(可选)
比如,下面是一个简单的电影 Schema:
---- ----- - --- --- ------ ------- --------- ------- ------- --------- - ---- ------ - --- --- ----- ------- - ---- ----- - ------- -------- --------- ----- ------ - ---- -------- - --------------- -------- ----------- ---- --------- ------ ------ --------------- ---- ------ -------- ----------- ---- --------- ------ ------ --------------- ----- -- -
2. 使用 DataLoader 来优化数据加载
在 GraphQL 中,一个查询中通常会包含多个嵌套的字段,这意味着多次从数据库中读取数据,将会对性能产生较大的影响。
为了解决这个问题,我们可以使用 DataLoader,它可以缓存请求,然后批量处理数据。这样,我们就可以在一个请求中获取所有数据,而不需要多次查询数据库。
比如,假设我们有一个查询返回所有电影及电影演员的姓名:
- ------ - -- ----- ------ - ---- - - -
如果没有 DataLoader,GraphQL 服务器会为每个电影和演员姓名分别从数据库开始查询。但是,如果启用 DataLoader,请求将会被缓存并批量处理,从而获得更好的性能。
3. 使用 Context 传递环境信息
在 GraphQL 中,Context 对象在整个查询过程中被传递,并许多库都会支持在 Context 中存储会话、用户授权信息等相关信息。
使用 Context 可以使得在 Resolver 函数之间传递状态信息变得更加容易。
比如,我们可以将用户认证信息,在 Resolver 中通过 Context 传递给查询、修改、删除函数:
----- -------- ---------------- - -- -- - ---- -- - ----- ----- - ----- ------------------- -- ----- -- ---------------------- - ------ ------ - ---- - ----- --- ---------------------- - - ----- --------- - - ------ - ------ ------------- -- --------- - --------- -------- ----- - ---- -- -- - -- ------- - ----- --- ---------------------- - ------ ------------------ -- ------------ -------- ----- - ---- -- -- - -- ------- - ----- --- ---------------------- - ------ ------------------ -- ------------ -------- ----- - ---- -- -- - -- ------- - ----- --- ---------------------- - ------ ------------------ - - --
4. 参数验证
GraphQL 请求可以包含很多参数,如果没有良好的参数验证机制,则有可能导致不良后果,比如 SQL 注入攻击。
为了避免这种情况,我们需要在 GraphQL 服务器上实施参数验证,可以使用一些现有的库,例如 Joi 或 Yup。
下面是一个使用 Joi 进行参数验证的例子:
----- --- - --------------------- ----- ----------- - ------------ ------ ------------------------ ----------- ---------------------------------- --------- ---------------------------------------------------- --- ----- --------- - - --------- - --------- -------- ----- -- - ----- - ----- - - --------------------------- -- ------- - ----- --- --------------------- - ------ ------------------ - - --
最佳实践
1. 分层结构
对于大型的 GraphQL API,我们应该考虑将业务逻辑与数据层分离,这样可以使代码更具可读性和可维护性。
我们可以将 Resolver 的实现放在独立的服务中,并使用 Repository 模式来处理数据操作。这样可以将 Resolver 与数据访问分离,更容易进行单元测试、集成测试等。
--- --- --- ---------- --- ------------------ --- ------- --- --------------- --- ----- --- ------------ --- ------------ --- ---------
2. 使用 Dataloader 和 Batch
在处理关系型数据时,批量获取数据和使用 DataLoader 可以极大提高 GraphQL API 的性能。
在 Apollo Server 中使用 DataLoader 很简单。我们只需要定义一个数据加载器,然后在 Resolver 函数中使用。
----- ---------- - ---------------------- ----- ----------- - --- ---------------- -- - ------ ---------------------- --- ----- --------- - - ------ - ------ --- - -- -- -- - ------ -------------------- - - --
Batching 也是提高性能的另一种方式。Batching 允许多个请求在一个请求中处理,这样就可以避免重复查询。
3. 利用 Fragment 提高查询可读性
在 GraphQL 中,查询通常包含嵌套的字段,这会导致查询变得冗长且难以理解。为了优化查询的可读性,我们可以使用 Fragment。
Fragment 允许我们定义一个可复用的字段集合,然后将其应用到查询中。
-------- ----------- -- ----- - ---- --- - ----- - --------- -- - ----- -------- - ---- --- - ------ - -------------- - - -
在这个例子中,actorFields 可以在我们的查询中被多次使用,使我们的查询代码更加简洁和易于理解。
4. 明确错误信息
GraphQL 返回的错误信息可能不够明确或不够详细,这可能会使开发更加困难。
为了提高 GraphQL 的错误信息质量,我们可以捕获并以标准的格式返回错误信息。GraphQL 提供了一个标准的错误结构,其中包含了错误信息、位置和路径。
- --------- - - ---------- --------------- ------------ - - ------- -- --------- - - -- ------- - ------- - - -- ------- - -------- ---- - -
5. 启用缓存
GraphQL 是一种更强大的查询语言,可以提高服务器和客户端的性能。但是,它也会带来一些挑战,例如在重复查询时需要消耗更多的计算资源。
为了避免这个问题,我们可以启用缓存。GraphQL API 的缓存可以提高性能并减少服务器的负载。
我们可以使用一些现有的缓存库,比如 Redis,或者使用一些各种云提供商所提供的缓存服务。
结论
GraphQL 作为一种新兴的技术,已经在很多公司和团队中被广泛使用。在本文中,我们介绍了一些 GraphQL 服务器端 API 设计的规范和最佳实践,并希望它可以帮助您更好地设计出高效和易用的 GraphQL API。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6700d846c842884a45a8df06