用10分钟快速入门GraphQL
这是为了6/28举办的GraphQL之夜而准备的资料。



以下是目前为止所了解的。
-
- クエリは独自言語みたい
-
- クエリを変えることで柔軟にデータをとってこれそう
- クエリと結果の見た目が似てるのは分かりやすそう(主観)
但是,为什么创建了Facebook?
Facebook 的情况
-
- 数十億ユーザから膨大なリクエストがくる
-
- 新興国の低速なネットワークからのモバイル接続も多い
- アップデートされないモバイルアプリもサポートする
换句话说
-
- リクエスト回数は可能な限り減らしたい
-
- 後方互換を維持しながら API を開発したい
-
- 無駄なデータを送りたくない
- (大規模開発なので型安全も欲しい)
我们可能有着不同的规模,但我们是否也面临着类似的问题?
为什么旧有的方式失败了?
请参考旧版 graphql.org 页面的详细信息(互联网档案馆)。
与REST相比
-
- 複雑なデータを取得しようとするとリクエスト回数が増える
-
- 後方互換を保ちながら拡張すると送信するデータが増える
後方非互換なバージョンが増えると管理が大変
型が標準的にはついてこない
对比 “专用 API”
-
- 巨大システムではメンテンナンスが大変
- REST 同様古いクライアントを壊さないために注意が必要
GraphQL 是怎么样的呢?
-
- GraphQL API そのものにはバージョンという概念はない。
https://api.github.com/graphql
field 単位で @deprecated にする
クライアントが必要な field だけを返すので、新しい field を追加しても既存のクライアントへのレスポンスが変わらない
1 つのクエリで複数のデータを取ってこれるので、何度も API リクエストする必要がない
型が強制される
对于字段和类型,暂不讨论。

这可能是个常见问题。
Q. 独自语言的学习成本是多少?
不是零,但和SQL之类的相比就一点不值一提。
Q:必须使用Node.js?
A. 没有那回事
GraphQL是一种用于API的查询语言,同时也是一个用于使用现有数据来满足这些查询的运行时。
GraphQL = 查询语言 + 运行时
规范和实现完全分离,大多数主要语言都已经有了运行时环境。(Facebook 内部似乎使用的是 Haskell 制作的)
Q: 后端必须使用图数据库吗?
A. 不可能的事情
DB是无所谓的,也可以跨多个。例如,在AWS AppSync中,可以跨Amazon DynamoDB、Amazon Elasticsearch、AWS Lambda进行使用。
A. 这个可行吗?
A. 可能性很低遭遇悲惨的结果(但有些语言可能会更加突显牺牲者感)。
虽然采取的例子越来越多,但工具的成熟度在每种语言中有很大的差异。与REST等相比,生态系统仍然不够成熟。
由于GraphQL的灵活性,可以随意发送大规模查询,但却存在没有标准的解决方法的问题。个人而言,我有些担心将其用作公开API。
你听说过DB的负荷很高吗?
如果正确面对问题,基本上是没问题的。
如果不经过考虑地进行实施,就会变得这样,但是如果使用类似于dataloader的工具进行正确的实施,也有可能减少数据库访问次数,而不是减少多个REST API请求。对于dataloader,应该针对各种编程语言都有实施。
总结
-
- GraphQL を作ったモチベーションは我々にも通じる
-
- GraphQL は仕様と実装で構成される
-
- エコシステムは発展途上
dataloader
Apollo
Relay
AWS AppSync
etc.
みんなで使って知見を(願わくば Qiita で)共有しよう
附加提示:为什么叫做 GraphQL?
(这是我个人的看法)
应用程序的数据可以解释为图形。

尝试使用以下查询来应用于此图表。
query {
# id が 1 の Article の
article(id: 1) {
# author の name と
author { name }
# likers の name をとってくる
likers { name }
}
}

{
"data": {
"article": {
"author": {
"name": "yuku"
},
"likers": [
{ "name": "htomine" },
{ "name": "tomoasleep" }
]
}
}
}
因为它是用于查询图形的语言,所以它是图形查询语言。
额外内容2: Qiita中的案例
GraphQL 是一种以客户端获取数据为中心的系统,但在 Qiita 中也部分地在服务器渲染时使用。

希望在服务器上创建初始数据以及按下“阅读更多”按钮时使用JS获取的JSON数据获取过程中实现DRY(Don’t Repeat Yourself)的目标。
class HomeController < ApplicationController
# `load_graphql_from_client` はファイルを読み込んで文字列として返すメソッド。
TAG_FEED_QUERY = <<~GRAPHQL
query {
tagFeed(first: 20) {
...TagFeed
}
}
#{load_graphql_from_client('TagFeedFragment')}
GRAPHQL
def tag_feed
result = execute_graphql(TAG_FEED_QUERY)
@tag_feed = result.data.tag_feed
end
end
fragment TagFeed on TagFeedConnection {
# ...
}
= tag.div(data: { props: @tag_feed })
這個視圖所生成的HTML形式如下:
<div data-props="{JSON}"/>
JSON由TagFeedFragment.graphql确定。通过apollo-codegen可以生成TypeScript类型,因此可以安全地从TypeScript中获取。
import { TagFeedFragment } from "./types-generated-by-apollo-codegen"
const props: TagFeedFragment = JSON.parse(el.dataset.props)
可以使用之前的片段从客户端向服务器发出查询。
import TagFeed from "./graphql/TagFeedFragment"
const query = `
query ($after: String!) {
tagFeed(after: $after, first: 20) {
...TagFeed
}
}
${TagFeed}
`
const result = await post('/graphql', query, { after: "Mx==" })
const tagFeed: TagFeedFragment = result.data.tagFeed
如此HTML中嵌入的数据与从客户端异步获取的数据一致,而且类型也匹配,非常令人高兴。