原文出处 Designing Powerful APIs with GraphQL Query Parameters
GraphQL API 设计的学习与最佳实践
GraphQL 查询提供了一种有效的方式来获取数据,甚至可以跨越多种语言。这使得数据层上有很好的抽象层,但有时候需要更多,来满足现代应用程序对特殊数据的需求。
我们的 GraphQL API 通过暴露不同的请求参数,来让客户端控制数据,并给予开发者更好的体验(DX)。类似于我们的嵌套变更语法,这也被越来越多的公司采用。我们 Graphcool 很高兴可以在 GraphQL 社区分享这一强大的最佳设计实践 GraphQL API。
本文探讨了我们的部分 GraphQL API 功能,包含:
过滤:通过用一个或多个匹配规则来过滤节点。
排序:由一个字段来升序或降序集合。
分页:在不同的页面中组合查询到的节点,包括前进或者向后查询。
过滤可以降低客户端的复杂度
你通常会想要查询数据的特殊部分。以一部电影的数据库为例子,你可能会查询在某个特定日子后的电影或者是有特别名字的。当然你总是可以查询所有的电影,并在客户端侧过滤他们,而这会导致不必要的数据--这是 GraphQL 可以避免的。
这是个使用 GraphQL 的好例子 查参!通过添加 filter
参数到查询里面,以上场景可以被迅速解决。如果你想要名称是《黑暗骑士》 的电影,你只需要在 filters
里面指定 title
字段就好了:
query darkKnightMovie { allMovies(filter: { title: "The Dark Knight" }) { releaseDate } }
通过名称过滤可以有效的获取单个电影。实际上,过滤系统比这还要更加强大,因为它编码 布尔代数。通过逻辑操作可以有更高层次的表现。
你可以在过滤条件中结合 OR
和 AND
操作,来选择多部你感兴趣的电影。例如,如果你想要查询电影《盗梦空间》以及2009年后发布的名称是《黑暗骑士》的电影,你可以用 OR
来结合这两个查询条件。
query combineMovies { allMovies(filter: { OR: [{ AND: [{ releaseDate_gte: "2009" }, { title_starts_with: "The Dark Knight" }] }, { title: "Inception" }] }) { title releaseDate } }
在数据需求上,通过提供 filter
查询参数,服务端做着繁重的工作,同时客户端保持完全的控制。这就生成了清晰并且有表象的 API ,并分离前后端之间的顾虑。
表达甚至更加复杂的数据需求
一个经典的需求就是数据排序 - 这又是通过服务端要比客户端好的地方。让我们结合数据排序和过滤器。
这次我们想要2009年后发布的电影的演员。filter
参数对这类请求有着强大系统。我们可以用 movies_some
并嵌套 releaseDate_gte:2009
,这个含义是我们想要的演员,其饰演的_部分_电影能够满足嵌套条件。
最重要的是,我们通过 orderBy: name_ASC
字段来排序。
query actorsAfter2009 { allActors( filter: { movies_some: { releaseDate_gte: "2009" } } first: 3 orderBy: name_ASC ) { name movies { title } } }
像这样结合过滤器和排序参数,可以让你简单的表达甚至更加复杂的数据请求。我们也可以用 movies_none
或者 movies_all
来表示查找的演员的所有电影_没有_或者_全部_满足的这些条件。
如果你仔细看,还会在上面的查询中发现 first: 3
参数。让我们看看这是什么
在相同规格的页面上浏览数据
想象一下一个罗列电影及其演员的网站。你的数据可能包含数千部电影,每部都包含很多演员。一个典型的场景是一次只展示几部电影,并允许用户向前或向后查询浏览整个电影列表。
在这里,你可以在查询中镜像表示参数,只获取现在需要的数据,来替代一次性获取所有数据的做法。这再次大大地简化客户端需要的逻辑,并且减少需要发送的数据。这种方式也叫做offset-base pagination。一个甚至更先进的分页变种叫做 cursor-based pagination,这也是通过结合 first
与 after
或者 last
与 before
来实现的。这里我们将重点关注偏移分页。
翻页参数与过滤器和排序无缝集成。通过这个方式,我们不再用简单的查询来满足复杂的请求。我们看看下面的查询是如何应用我们所学到的。我们展示2000年后发布的头两部电影,通过其发布时间来排序,并且对其演员名单排序。你自己看看:
query paginateMoviesAndActors($movieFirst: Int, $movieSkip: Int, $actorFirst: Int, $actorSkip: Int, $movieOrder: MovieOrderBy) { allMovies ( filter: { releaseDate_gt: "2000" } orderBy: $movieOrder first: $movieFirst skip: $movieSkip ) { title actors( orderBy: name_ASC, first: $actorFirst, skip: $actorSkip ) { name } releaseDate } }
你可以通过提供的查询变量来实践,看看他们有什么效果。例如,你可以设 movieSkip
为 2
而 movieOrder
为 title_DESC
,然后再查询。将会按照名字的降序返回第二页电影。
总结
我们精心设计 GraphQL APIs,让客户端应用有很好的灵活性和控制。通过不同的规则来 过滤 和 排序,以及 分页 你的数据,你可以准确的表达你想要的数据,让后端找出来。.
你对我们的 API 有没有什么疑问?可以参与我们的 Slack 频道 来讨论,或者浏览 文档 获取更多信息。如果你还没有账户,可以在 这里 Graphcool 注册。