PRF&PUB:20170101 GraphQL In Use Building a Blogging Engine API with Golang and PostgreSQL.md

@ictlyh 翻译的很好很专业~ https://linux.cn/article-8524-1.html
This commit is contained in:
wxy 2017-05-19 11:19:09 +08:00
parent 9410d26a5f
commit e8c94f4a78

View File

@ -9,15 +9,15 @@ GraphQL 在生产环境中似乎难以使用:虽然对于建模功能来说图
* 三种类型的资源(用户、博文以及评论)支持多种功能(创建用户、创建博文、给博文添加评论、关注其它用户的博文和评论,等等。)
* 使用 PostgreSQL 作为后端数据存储(选择它因为它是一个流行的关系型数据库)。
* 使用 Golang开发 API 的一个流行语言)进行 API 实现
* 使用 Golang开发 API 的一个流行语言)实现 API
我们会比较简单的 GraphQL 实现和纯 REST 替代方案,在一种普通场景(呈现博客文章页面)下对比它们的实现复杂性和效率。
### 介绍
GraphQL 是一种 IDLInterface Definition Language接口定义语言设计者定义数据类型和并把数据建模为一个图。每个顶点都是一种数据类型的一个实例边代表了节点之间的关系。这种方式非常灵活能适应任何业务领域。然而问题是设计过程更加复杂而且传统的数据存储不能很好地映射到图模型。阅读_附录1_了解更多关于这个问题的详细信息。
GraphQL 是一种 IDLInterface Definition Language接口定义语言设计者定义数据类型和并把数据建模为一个图graph。每个顶点都是一种数据类型的一个实例边代表了节点之间的关系。这种方式非常灵活能适应任何业务领域。然而问题是设计过程更加复杂而且传统的数据存储不能很好地映射到图模型。阅读_附录1_了解更多关于这个问题的详细信息。
GraphQL 在 2014 年由 Facebook 的工程师团队首次提出。尽管它的优点和功能非常有趣而且引人注目,它并没有得到大规模应用。开发者需要权衡 REST 的设计简单性、熟悉性、丰富的工具和 GraphQL 不会受限于 CRUDLCTT 译注Create、Read、Update、Delete 以及网络性能(它优化了往返服务器的网络)的灵活性。
GraphQL 在 2014 年由 Facebook 的工程师团队首次提出。尽管它的优点和功能非常有趣而且引人注目,它并没有得到大规模应用。开发者需要权衡 REST 的设计简单性、熟悉性、丰富的工具和 GraphQL 不会受限于 CRUDLCTT 译注Create、Read、Update、Delete 以及网络性能(它优化了往返服务器的网络)的灵活性。
大部分关于 GraphQL 的教程和指南都跳过了从数据存储获取数据以便解决查询的问题。也就是,如何使用通用目的、流行存储方案(例如关系型数据库)为 GraphQL API 设计一个支持高效数据提取的数据库。
@ -37,7 +37,7 @@ GraphQL 在 2014 年由 Facebook 的工程师团队首次提出。尽管它的
### 在 GraphQL 中建模一个博客引擎
_列表1_包括了博客引擎 API 的全部模式。它显示了组成图的顶点的数据类型。顶点之间的关系,也就是边,被建模为指定类型的属性。
下述_列表1_包括了博客引擎 API 的全部模式。它显示了组成图的顶点的数据类型。顶点之间的关系,也就是边,被建模为指定类型的属性。
```
type User {
@ -86,7 +86,7 @@ type Mutation {
_列表1_
模式使用 GraphQL DSL 编写,它用于定义自定义数据类型,例如 `User`、`Post` 和 `Comment`。该语言也提供了一系列原始数据类型,例如 `String`、`Boolean` 和 `ID`(是`String` 的别名,但是有顶点唯一标识符的额外语义)。
模式使用 GraphQL DSL 编写,它用于定义自定义数据类型,例如 `User`、`Post` 和 `Comment`。该语言也提供了一系列原始数据类型,例如 `String`、`Boolean` 和 `ID`是`String` 的别名,但是有顶点唯一标识符的额外语义)。
`Query` 和 `Mutation` 是语法解析器能识别并用于查询图的可选类型。从 GraphQL API 读取数据等同于遍历图。需要提供这样一个起始顶点;该角色通过 `Query` 类型来实现。在这种情况中,所有图的查询都要从一个由 id `user(id:ID!)` 指定的用户开始。对于写数据,定义了 `Mutation` 顶点。它提供了一系列操作建模为能遍历并返回新创建顶点类型的参数化属性。_列表2_是这些查询的一些例子。
@ -99,7 +99,7 @@ _列表1_
* 也可以把它们组合起来,例如 `[Comment!]!` 表示一个非空 Comment 顶点链表,其中 `[]`、`[Comment]` 是有效的,但 `null, [null], [Comment, null]` 就不是。
_列表2_ 包括一系列用于博客 API 的 _curl_ 命令,它们会使用 mutation 填充图然后查询图以便获取数据。要运行它们,按照 [topliceanu/graphql-go-example][3] 仓库中的指令编译并运行服务。
_列表2_ 包括一系列用于博客 API 的 `curl` 命令,它们会使用 mutation 填充图然后查询图以便获取数据。要运行它们,按照 [topliceanu/graphql-go-example][3] 仓库中的指令编译并运行服务。
```
# 创建用户 1、2 和 3 的更改。更改和查询类似,在该情景中我们检索新创建用户的 id 和 email。
@ -143,7 +143,10 @@ _列表2_
### 设计 PostgreSQL 数据库
关系型数据库的设计一如以往由避免数据冗余的需求驱动。选择该方式有两个原因1\. 表明实现 GraphQL API 不需要定制化的数据库技术或者学习和使用新的设计技巧。2\. 表明 GraphQL API 能在现有的数据库之上创建,更具体地说,最初设计用于 REST 后端甚至传统的呈现 HTML 站点的服务器端数据库。
关系型数据库的设计,一如以往,由避免数据冗余的需求驱动。选择该方式有两个原因:
1. 表明实现 GraphQL API 不需要定制化的数据库技术或者学习和使用新的设计技巧。
2. 表明 GraphQL API 能在现有的数据库之上创建,更具体地说,最初设计用于 REST 后端甚至传统的呈现 HTML 站点的服务器端数据库。
阅读 _附录1_ 了解关于关系型和图数据库在构建 GraphQL API 方面的区别。_列表3_ 显示了用于创建新数据库的 SQL 命令。数据库模式和 GraphQL 模式相对应。为了支持 `follow/unfollow` 更改,需要添加 `followers` 关系。
@ -176,7 +179,7 @@ _列表3_
### Golang API 实现
本项目使用的用 Go 实现的 GraphQL 语法解析器是 `github.com/graphql-go/graphql`。它包括一个查询解析器,但不包括模式解析器。这要求开发者利用库提供的结构使用 Go 构建 GraphQL 模式。这和 [nodejs 实现][3] 不同,后者提供了一个模式解析器并为数据获取暴露了钩子。因此 `列表1` 中的模式只是作为指导使用,需要转化为 Golang 代码。然而这个_“限制”_提供了与抽象级别对等的机会并且了解模式如何和用于检索数据的图遍历模型相关。_列表4_ 显示了 `Comment` 顶点类型的实现:
本项目使用的用 Go 实现的 GraphQL 语法解析器是 `github.com/graphql-go/graphql`。它包括一个查询解析器,但不包括模式解析器。这要求开发者利用库提供的结构使用 Go 构建 GraphQL 模式。这和 [nodejs 实现][3] 不同,后者提供了一个模式解析器并为数据获取暴露了钩子。因此 _列表1_ 中的模式只是作为指导使用,需要转化为 Golang 代码。然而这个_“限制”_提供了与抽象级别对等的机会并且了解模式如何和用于检索数据的图遍历模型相关。_列表4_ 显示了 `Comment` 顶点类型的实现:
```
var CommentType = graphql.NewObject(graphql.ObjectConfig{
@ -348,9 +351,9 @@ _列表5_
对于这种情况,对数据库的查询次数是故意相同的,但是到 API 服务器的 HTTP 请求已经减少到只有一个。我们认为在这种类型的应用程序中通过互联网的 HTTP 请求是最昂贵的。
为了获取 GraphQL 的优势,后端并不需要进行特别设计,从 REST 到 GraphQL 的转换可以逐步完成。这使得可以测量性能提升和优化。从这一点API 设计者可以开始优化(潜在的合并) SQL 查询从而提高性能。缓存的机会在数据库和 API 级别都大大增加。
为了利用 GraphQL 的优势,后端并不需要进行特别设计,从 REST 到 GraphQL 的转换可以逐步完成。这使得可以测量性能提升和优化。从这一点API 设计者可以开始优化(潜在的合并) SQL 查询从而提高性能。缓存的机会在数据库和 API 级别都大大增加。
SQL 之上的抽象(例如 ORM 层)通常会和 `n+1` 问题想抵触。在 REST 事例的步骤 4 中,客户端可能不得不在单独的请求中为每个评论的作者请求关注状态。这是因为在 REST 中没有标准的方式来表达两个以上资源之间的关系,而 GraphQL 旨在通过使用嵌套查询来防止这类问题。这里我们通过获取用户的所有关注者进行欺骗。我们向客户推荐确定评论和关注作者用户的逻辑。
SQL 之上的抽象(例如 ORM 层)通常会和 `n+1` 问题相抵触。在 REST 示例的步骤 4 中,客户端可能不得不在单独的请求中为每个评论的作者请求关注状态。这是因为在 REST 中没有标准的方式来表达两个以上资源之间的关系,而 GraphQL 旨在通过使用嵌套查询来防止这类问题。这里我们通过获取用户的所有关注者来作弊。我们向客户提出了如何确定评论并关注了作者的用户的逻辑。
另一个区别是获取比客户端所需更多的数据,以免破坏 REST 资源抽象。这对于用于解析和存储不需要数据的带宽消耗和电池寿命非常重要。
@ -358,7 +361,7 @@ SQL 之上的抽象(例如 ORM 层)通常会和 `n+1` 问题想抵触。在
GraphQL 是 REST 的一个可用替代方案,因为:
* 尽管设计 API 更加困难,该过程可以逐步完成。也是由于这个原因,从 REST 转换到 GraphQL 非常容易,两个流程可以没有任何问题地共存。
* 尽管设计 API 更加困难,该过程可以逐步完成。也是由于这个原因,从 REST 转换到 GraphQL 非常容易,两个流程可以没有任何问题地共存。
* 在网络请求方面更加高效,即使是类似本博客中的简单实现。它还提供了更多查询优化和结果缓存的机会。
* 在用于解析结果的带宽消耗和 CPU 周期方面它更加高效,因为它只返回呈现页面所需的数据。
@ -370,15 +373,15 @@ REST 仍然非常有用,如果:
### 附录1图数据库和高效数据存储
尽管将应用领域数据想象为一个图非常直观,正如这篇博文介绍的那样,但是支持这种接口的高效数据存储问题仍然没有解决。
尽管将应用领域数据想象为一个图非常直观,正如这篇博文介绍的那样,但是支持这种接口的高效数据存储问题仍然没有解决。
近年来图数据库变得越来越流行。通过将 GraphQL 查询转换为特定的图数据库查询语言从而延迟解决请求的复杂性似乎是一种可行的方案。
问题是和关系型数据库相比图并不是一种高效的数据结构。图中一个顶点可能有到任何其它顶点的连接,访问模式比较难以预测因此提供了较少的优化机会。
问题是和关系型数据库相比图并不是一种高效的数据结构。图中一个顶点可能有到任何其它顶点的连接,访问模式比较难以预测因此提供了较少的优化机会。
例如缓存的问题,为了快速访问需要将哪些顶点保存在内存中?通用缓存算法在图遍历场景中可能没那么高效。
数据库分片问题:把数据库切分为更小、没有交叉的数据库并保存到独立的硬件。在学术上,最小切割的图划分问题已经得到了很好的理解,但可能是次优的而且由于病态的最坏情况可能导致高度不平衡切割。
数据库分片问题:把数据库切分为更小、没有交叉的数据库并保存到独立的硬件。在学术上,最小切割的图划分问题已经得到了很好的理解,但可能是次优的而且由于病态的最坏情况可能导致高度不平衡切割。
在关系型数据库中数据被建模为记录行或者元组和列表和数据库名称都只是简单的命名空间。大部分数据库都是面向行的意味着每个记录都是一个连续的内存块一个表中的所有记录在磁盘上一个接一个地整齐地打包通常按照某个关键列排序。这非常高效因为这是物理存储最优的工作方式。HDD 最昂贵的操作是将磁头移动到磁盘上的另一个扇区,因此最小化此类访问非常重要。
@ -392,7 +395,7 @@ via: http://alexandrutopliceanu.ro/post/graphql-with-go-and-postgresql
作者:[Alexandru Topliceanu][a]
译者:[ictlyh](https://github.com/ictlyh)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出