接上篇 —— 如何使用 GraphQL-进阶教程:客户端 —— 继续翻译How to GraphQL 系列教程。
了解 GraphQL 服务端的主要概念,如何执行带有解析器功能的 GraphQL 查询以及批处理多个请求。
基础和进阶系列翻译已完成:
GraphQL 通常被解释为针对前端的 API 技术,因为它使客户端能够以比以前更好的方式获取数据。但是,API 本身当然是在服务端实现的。对服务端来说也有很多好处,因为 GraphQL 使服务端开发者可以专注于描述可用数据,而不是实现和优化特定端点。
GraphQL 执行
GraphQL 不仅指定一种描述 schema 的方法和一种从 schema 中检索数据查询语言,还指定了用于将这些查询转换为结果的实际执行算法。该算法的核心非常简单:逐字段遍历查询,为每个字段执行“解析器(resolvers)”。如下,假设我们具有以下 schema:
1 | type Query { |
以下是我们发送到具有该 schema 的服务端的查询:
1 | query { |
首先要看的是查询中的每个字段都可以与一个类型相关联:
1 | query: Query { |
现在,我们可以轻松地在服务端中找到要在每个字段运行的解析器。执行从查询类型开始而且广度优先。这意味着我们首先运行 Query.author
的解析器。然后获取该解析器的结果,并将其传递给其子级,即 Author.posts
的解析器。再下一级的结果是一个列表,因此在本例中,执行算法一次只能运行在一个项目上。如下所示:
1 | Query.author(root, { id: 'abc' }, context) -> author |
最后,执行算法将所有内容放到正确的格式中,然后返回结果。
需要注意的是大多数 GraphQL 服务端实现都提供“默认解析器”,因此不必为每个字段都指定解析器功能。例如,在 GraphQL.js 中,当解析器的父对象包含名称正确的字段时无需指定解析器。
阅读 Apollo 博客的“GraphQL Explained” post中详细了解 GraphQL 执行。
批量解析
你可能会注意到上述执行策略有些幼稚。例如,如果有一个从后端 API 或数据库中获取的解析器,则在执行一个查询期间,该后端可能会被调用多次。比如想要获得几篇文章的作者,如下所示:
1 | query { |
如果这些是博客上的帖子,则很多帖子可能具有相同的作者。因此,如果我们需要进行 API 调用以请求每个作者对象,则可能会意外地对同一个对象发出多个请求。例如:
1 | fetch('/authors/1'); |
这个问题的解决方式就是让请求更智能。我们可以将请求函数包装在一个工具函数中,该工具程函数将等待所有解析器运行,然后确保每个项目仅请求一次:
1 | authorLoader = new AuthorLoader(); |
可以做得更好吗?可以的,如果 API 支持批处理请求,那么只需对后端执行一次请求,如下所示:
1 | fetch('/authors?ids=1,2'); |
这也可以封装在上面的加载器中。
在 JavaScript 中,可以使用名为DataLoader的工具函数来实现上述策略,并且对于其他语言也有类似的实用工具。
前端记事本,不定期更新,欢迎关注!