【書籍】踏入GraphQL的第一本书籍 – 学习笔记-

这是什么?

初めてのGraphQL

这篇文章是关于总结学习了O’Reilly Japan出版的《初めてのGraphQL》一书的内容。随着阅读的进行,我会逐步添加内容。

索引

1章 欢迎来到GraphQL
2章 图论
3章 GraphQL查询语言
4章 架构设计
5章 GraphQL服务器的实现
6章 GraphQL客户端的实现
7章 实际应用GraphQL

欢迎来到第一章:GraphQL。

1.1 GraphQL是什么

    • インターネットが広く普及しても、「特定の場所にあるデータをいかにして素早く読み込むか」という問題がつきまとう

早く・快適なアプリケーションの方が多くの人々を引き込むから

GraphQL

APIを利用する際に使う問い合わせ言語
必要なデータだけリクエストの際に指定するのが特徴
クエリが入れ子になっている場合は記載されたデータを一回のリクエストで受け取れる

在使用Star Wars API的服务器上使用GraphQL
【请求文】
我想获取personID为5的数据中的”name”、”birthYear”和”created”信息。

query {
  person(personID:5){
    name
    birthYear
    created
  }
}

【回复文】

{
  "data": {
    "person": {
      "name": "Leia Organa",
      "birthYear": "19BBY",
      "created": "2014-12-10T15:20:09.791000Z"
    }
  }
}

GraphQLの言語仕様

使用する言語に指定はない
JavaScriptでの実装例はGitHubで公開されている

GraphQLの設計原則

階層構造

クエリ(データベースへの命令文)は階層構造で記述する
フィールドは他のフィールドの入れ子
クエリとレスポンスは同じ構造

プロダクト中心

GraphQLは必要とされている言語や実行時間に応じて実装する

強い型付け

それぞれのフィールドが型を持つ

クライアントごとのクエリ

クライアントが欲する機能を提供する

自己参照

GraphQLは自身の型システムに問い合わせることができる

1.2 GraphQL的诞生

    • Facebookのエンジニアが自身のモバイルアプリを再設計する際に開発

APIとFQL(FacebookのSQL)を使っていたもののパフォーマンスに問題があった

データ通信の変遷

RPC

クライアントが遠隔地のコンピュータに要求をすることで特定の処理を実行し、データを受け取る
クライアント/サーバーモデルと情報の流れは同じ

SOAP

xml形式でエンコードしたメッセージを通信する
型システムを導入していたため、レスポンスがわかりやすかった
実装が複雑

REST

GET,PUT,POST,DELETEという操作を実行することでサーバーの状態を操作する
URIとクライアントが欲する情報が対応している

RESTの問題点

過剰なレスポンスデータ取得

RESTでは必要以上の情報をレスポンスで取得してしまい、アプリケーションの高速性を妨害する

過小なレスポンスデータ取得

必要なデータを取得できるように複数のエンドポイントでリクエストを実行する場合がある
複数のエンドポイントにリクエストを投げることで受け取るデータ量が更に増える

エンドポイントの管理

新たな機能を実装する際に「既に存在するエンドポイントを整理する」作業が発生するため、開発速度が低下する

GraphQLを「RESTにおける一つのエンドポイント」として実装することもできる

GraphQLのカンファレンス

GraphQL Summit
GraphQL Finland
GraphQL Europe

第二章_图论

    • グラフは身の回りの至る所に存在する

データ同士の関係性を図示するのに優れている

2.1 图论术语

    • ノード

各データの要素の部分(下図の丸の部分)

エッジ

各データ同士のつながりの部分(下図の青線の部分)

数式でグラフを記述

Gが一つのグラフを表す
Vがノードの要素を表す
Eがエッジの要素を表す

G=(V, E)\\

V =\{1, 2, 3, 4, 5\}\\

E = \{\{1,2\},\{1,3\},\{1,5\},\{2,3\},\{2,4\},\{2,5\},\{3,4\},\{4,5\}\}
無向グラフ
    • グラフの種類

無向グラフ(上図)

エッジに方向性がない

有向グラフ(下図)

エッジに方向性がある
数式で表す際にも方向性を配慮する必要がある

G=(V, E)\\

V =\{1, 2, 3, 4, 5\}\\

E = (\{1,3\},\{1,5\},\{2,4\},\{2,5\},\{3,2\},\{4,3\})
有向グラフ

2.1 图形理论的历史

ケーニヒスベルクの七つの橋問題(Wikipedia)

橋で繋がった陸地があるときに、同じ橋を渡らずに全ての陸地を踏破できるか、を証明する問題
レオンハルトオイラーが地形をグラフに置き変えることで、ケーニヒスベルクの橋では踏破できないことを証明した

オイラーの定理(Wikipedia)

以下の条件を持つグラフを「オイラーグラフ」と言い、一筆書きが可能である

グラフの全ての頂点の次数が偶数
グラフの頂点のうち、次数が奇数であるものがちょうど2つ

2.3 树图

ノードが階層的に並べられているグラフ

例. 組織図, 家系図

最上位に存在するノード
エッジにより繋がっている2つノードのうち、根に近いノードを「親」、遠いノードを「子」という
子ノードがないノードを「葉」という

部分木

木構造の中に存在する部分的な木構造
例. HTMLでいうところのbodyタグなど

二分木

子がたかだか二つしかない木のこと
条件をつけてグラフ化することでより高速に求めるノードまでたどり着ける

2.4 现实世界的图表

    • Twitter

有向グラフ
AがBをフォローしていても、BがAをフォローしていない場合が存在するため

Facebook

無向グラフ
ユーザー同士が相互にフォローするため、ノードに方向性がない

第三章_ GraphQL查询语言

    • SQL

データベースに格納されているデータを操作するための言語
少数のコマンドでデータを操作できる(SELECT, INSERT, UPDATE, DELETE)

RESTにもこの思想が引き継がれている

データへの操作(GET, POST, PUT, DELETE)
操作対象の指定はエンドポイント
例. GET /user/1:ユーザーデータを取得(GET)する

SQLとGraphQLの違い

使う環境

SQL:データベース上
GraphQL:API上

構文

SQL:INSERT, UPDATE, DELETE
GraphQL:Mutation

通信によるデータの変更を監視する機能(Subscription)がGraphQLにある

3.1 GraphQL API的有用工具

    • GraphiQL(GitHub)

ブラウザ上で動作するGraphQL APIのための統合開発ツール
入力補完や構文エラーなどを表示してくれる

有向グラフ
    • GraphQL Playground(GitHub)

GraphiQLと異なる点

ヘッダーを書き換えることができる(5章で詳細)
デスクトップ版もHomebrewでインストールできる
URLで共有することも可能

公開GraphQL API

Star Wars API

Faceboolが作成
Star Wars APIをラップして作られた

GitHub API

GitHubの情報を閲覧/更新できる
クエリとMutationが可能

Yelp

クエリの作成と実行が可能

3.2 GraphQL查询

这里是用来后续使用的GraphQL API网站。

GraphQLの用語(参考になりそうなQuita)

ルート型

クエリの最初に指定されているやつ

例. query, mutation

データソースに対して行う操作を表現している
ドキュメントに各ルート型に対して実行できるフィールドが記載されている

フィールド

クエリで取得することができるデータソース
ドキュメントにフィールドの種類や要素が記載されている

選択セット

クエリ文で{…}の記号で囲んだ部分
ドキュメントに「選択セットで指定できるフィールド」が記載されている

サーバーからのレスポンスはクエリで指定したフィールドと同じものになる

执行请求(allLifts字段)

query{
  allLifts{
    name
    status
  }
}

回应

{
  "data": {
    "allLifts": [
      {
        "name": "Astra Express",
        "status": "OPEN"
      },
・・・・・・・・・・・・・・・・・・・・・・・・
    • クエリを同時に複数実行したい場合には一つのクエリにまとめる必要がある

 

    • フィールドは必要なものだけ記載すれば良い

 

    フィールド名は指定する名前: 変更したいフィールド名と書くことで変更できる(エイリアス)

执行请求(运行allLifts和allTrails字段)。

query {
  allLifts {
    name
    status
  }
  nya_n: allTrails {
    name
    status
  }
}

回答

{
  "data": {
    "allLifts": [
      {
        "name": "Astra Express",
        "status": "OPEN"
      },
・・・・・・・・・・・・・・・・・・・・・・・・    
    ],
    "nya_n": [ #ここが「allTrails」から「nya_n」になっている
      {
        "name": "Blue Bird",
        "status": "CLOSED"
      },
・・・・・・・・・・・・・・・・・・・・・・・・
    クエリに引数を記載することでレスポンスのデータを絞ることができる

只显示 allLifts 状态为 OPEN 的请求。

query {
  allLifts (status: OPEN) {
    name
    status
  }
}

回应

{
  "data": {
    "allLifts": [
      {
        "name": "Astra Express",
        "status": "OPEN"
      },
・・・・・・・・・・・・・・・・・・・・・・・・
    オブジェクト型の中にオブジェクトを入れると、上位のオブジェクトに関連した詳細データを得るためのクエリを書くことが出来る(以下の例ではLift型の中にTrain型が内包されている)

搜索一个名为”jazz-cat”的滑雪场的一条可以坐上升机的滑雪道。

query {
  Lift (id: "jazz-cat") {
    name
    capacity
    trailAccess{
      name
      difficulty
    }
  }
}

回应

{
  "data": {
    "Lift": {
      "name": "Jazz Cat",
      "capacity": 2,
      "trailAccess": [
        {
          "name": "Goosebumps",
          "difficulty": "advanced"
        },
・・・・・・・・・・・・・・・・・・・・・・・・
    • フラグメント

クエリ内で繰り返して記述する部分があればfragmentを使うことで、表現を使いまわすことが出来る
定義方法 fragment フラグメント名 on fragment内の型{hoge}

query内で…フラグメント名と記載することで使える
フラグメント内で「最初に定義した以外の型」を使うことはできない

请求(请求爵士猫滑雪电梯和“河流冲刺”滑雪课程的信息)

query {
  Lift (id: "jazz-cat") {
    ...liftInfo
    trailAccess{
      ...trainInfo
    }
  }
  Trail(id: "river-run"){
    ...trainInfo
    accessedByLifts{
      ...liftInfo
    }
  }
}

fragment liftInfo on Lift{
  name
  status
  capacity
  night
  elevationGain
}

fragment trainInfo on Trail{
  name
  difficulty
}

回应

{
  "data": {
    "Lift": {
      "name": "Jazz Cat",
      "status": "OPEN",
      "capacity": 2,
      "night": false,
      "elevationGain": 1230,
      "trailAccess": [
        {
          "name": "Goosebumps",
          "difficulty": "advanced"
        },
・・・・・・・・・・・・・・・・・・・・・・・・
"Trail": {
      "name": "River Run",
      "difficulty": "intermediate",
      "accessedByLifts": [
        {
          "name": "Jazz Cat",
          "status": "OPEN",
          "capacity": 2,
          "night": false,
          "elevationGain": 1230
・・・・・・・・・・・・・・・・・・・・・・・・
    • fragmentはインラインで記述することも可能(…on fragment内の型{hoge})

 

    ユニオン型のフィールドでfragmentを使う場合は、選択セット内に該当する型をそれぞれ記載することで個別に定義ができる

获取请求(获取具有多个类型的联合类型字段AgendaItem)。

query{
  agenda{
    ...on Workout{
      name
      reps
    },
     ...on Studygroup{
      name
      subject
      students
    }
  }
}

3.3 变异

    • mutation

書き込みの操作を行うルート型
どのような操作ができるかはAPIスキーマで定義されている

在中国以母语将以下内容改述为中文,只需要一个选项:
请求(注册Jazz-cat名称的曲目,并接收ID和名称作为响应)。

mutaion {
  addSong(title: "jazz-cat", singer: "crazy cat", genre: "jazz") {
    id
    name
    }
}

回应

{
  "data": {
    "addSong": {
      "id": "doweaghdcoas",
      "name": "jazz-cat"
    }
}
    • クエリ変数

mutaionの引数に変数を利用したい場合には以下のように書く

使用今天的最热歌曲标题(存储在变量today_top_song_title中的字符串)于突变请求中。

mutaion ($today_top_song_title:String!) { #ここで変数の型を指定する
  addSong(title: "$today_top_song_title", singer: "crazy cat", genre: "jazz") {
    id
    name
    }
}
{
  "today_top_song_title": "take five"
}

3.4 订阅

    • Subscription

サーバーが更新された時にクライアントにその情報を提供する
Facebookの「いいね」の自動更新

当接收到请求时(即电梯状态发生变化时),会获取name、capacity和status这三个参数。

subscription{
  liftStatusChange{
    name
    capacity
    status
  }
}

在其他选项卡上改变升降机状态时的回应

{
  "data": {
    "liftStatusChange": {
      "name": "Astra Express",
      "capacity": 3,
      "status": "HOLD"
    }
  }
}

3.5 反思

    • Introspection

APIのスキーマ(APIの使い方)を取得することができる
queryで__schemaを指定することで確認できる

接收可以在请求(query、mutation、subscription)中使用的所有字段。

query{
  __schema{
    queryType{
      ...typeFields
    }
    mutationType{
      ...typeFields
    }
    subscriptionType{
      ...typeFields
    }
  }
}
fragment typeFields on __Type{
  name
  fields{
    name
  }
}

回应

{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query",
        "fields": [
          {
            "name": "allLifts"
          },
          {
            "name": "allTrails"
          },
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
      "mutationType": {
        "name": "Mutation",
        "fields": [
          {
            "name": "setLiftStatus"
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
      "subscriptionType": {
        "name": "Subscription",
        "fields": [
          {
            "name": "liftStatusChange"
          },
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
}

3.6 – 抽象语法树

    • 抽象構文木

意味に関係にある情報のみを取り出した木構造
GraphQL APIにクエリを送信すると文字列は抽象構文木にパースされる

第四章_模式设计

最近,计划公开

第5章_实现GraphQL服务器

最近,计划公开

第6章实现GraphQL客户端。

最近计划公开

在实施GraphQL的第7章计划中

最近,计划公开。

广告
将在 10 秒后关闭
bannerAds