用10分钟快速入门GraphQL

这是为了6/28举办的GraphQL之夜而准备的资料。


スクリーンショット 2018-06-28 15.07.40.png

スクリーンショット 2018-06-28 15.08.09.png

スクリーンショット 2018-06-28 15.02.51.png

以下是目前为止所了解的。

    • クエリは独自言語みたい

 

    • クエリを変えることで柔軟にデータをとってこれそう

 

    クエリと結果の見た目が似てるのは分かりやすそう(主観)

但是,为什么创建了Facebook?


Facebook 的情况

    • 数十億ユーザから膨大なリクエストがくる

 

    • 新興国の低速なネットワークからのモバイル接続も多い

 

    アップデートされないモバイルアプリもサポートする

换句话说

    • リクエスト回数は可能な限り減らしたい

 

    • 後方互換を維持しながら API を開発したい

 

    • 無駄なデータを送りたくない

 

    (大規模開発なので型安全も欲しい)

我们可能有着不同的规模,但我们是否也面临着类似的问题?


为什么旧有的方式失败了?

请参考旧版 graphql.org 页面的详细信息(互联网档案馆)。

与REST相比

    • 複雑なデータを取得しようとするとリクエスト回数が増える

 

    • 後方互換を保ちながら拡張すると送信するデータが増える

後方非互換なバージョンが増えると管理が大変

型が標準的にはついてこない

对比 “专用 API”

    • 巨大システムではメンテンナンスが大変

 

    REST 同様古いクライアントを壊さないために注意が必要

GraphQL 是怎么样的呢?

    • GraphQL API そのものにはバージョンという概念はない。

https://api.github.com/graphql
field 単位で @deprecated にする

クライアントが必要な field だけを返すので、新しい field を追加しても既存のクライアントへのレスポンスが変わらない
1 つのクエリで複数のデータを取ってこれるので、何度も API リクエストする必要がない
型が強制される

对于字段和类型,暂不讨论。


image.png

这可能是个常见问题。

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?

(这是我个人的看法)

应用程序的数据可以解释为图形。

image.png

尝试使用以下查询来应用于此图表。

query {
  # id が 1 の Article の
  article(id: 1) {
    # author の name と
    author { name }
    # likers の name をとってくる
    likers { name }
  }
}
image.png
{
  "data": {
    "article": {
      "author": {
        "name": "yuku"
      },
      "likers": [
        { "name": "htomine" },
        { "name": "tomoasleep" }
      ]
    }
  }
}

因为它是用于查询图形的语言,所以它是图形查询语言。


额外内容2: Qiita中的案例

GraphQL 是一种以客户端获取数据为中心的系统,但在 Qiita 中也部分地在服务器渲染时使用。

https://gyazo.com/b0eb7d222524b0cc4df2b6d4ce44b480

希望在服务器上创建初始数据以及按下“阅读更多”按钮时使用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中嵌入的数据与从客户端异步获取的数据一致,而且类型也匹配,非常令人高兴。

bannerAds