$30 off During Our Annual Pro Sale. View Details »

2019-16 GraphQL

2019-16 GraphQL

Cybozu
PRO

July 31, 2019
Tweet

More Decks by Cybozu

Other Decks in Programming

Transcript

  1. 開運研修2019 スキーマファースト開発入門
    GraphQL 編
    ymmt

    View Slide

  2. Agenda
    ▌問い合わせ言語とは
    ▌GraphQL 概説
    ▌GraphQL サーバーの実装
    ▌GraphiQL でクエリを楽々開発
    ▌sabakan / CKE 連携の実装例
    ▌GraphQL vs OpenAPI vs gRPC

    View Slide

  3. 問い合わせ言語(Query Language)とは
    ▌利用者が指定した情報をデータベースから得る記法
    ⚫ SQL, LDAP, JSON Pointer, …
    ▌対象とするデータモデルに強く依存
    ⚫ SQL = Relational モデル
    ⚫ LDAP = LDAP Schema
    ⚫ JSON Pointer = JSON

    View Slide

  4. 問い合わせ言語がなぜ必要か
    データベースの内部実装を隠蔽したい
    • B-Tree で実装されているといった内容は隠したい
    複雑なデータ取得処理を何度も実装したくない
    • 汎用の問い合わせ(Query)実行エンジンさえあれば、
    問い合わせをテキストで書くだけで済む
    同じ問い合わせ言語で複数のシステムを利用したい
    • SQL を学べば、広範囲に役立つ

    View Slide

  5. GraphQL とは
    ▌Facebook が 2015 年に公開
    ⚫ 2018 年 11 月に GraphQL Foundation に移管
    ⚫ graphql.org で仕様などを公開
    ▌SQL に少し似たスキーマとクエリ言語の仕様
    ▌可能な操作
    ⚫ データの取得(Query)
    ⚫ データの変更(Mutation)
    ⚫ イベント購読(Subscription)

    View Slide

  6. GraphQL の特徴
    • データモデルと Query, Mutation, Subscription を定義
    • スキーマからサーバー実装・クライアント実装の一部を自動生成可能
    Schema First
    • 無限に複雑なクエリが書ける (DoS 注意)
    • 関連するデータを一つのクエリで一括取得できる
    データモデルが循環参照できる
    • 一般的な実装では応答形式は JSON
    • ブラウザやモバイルの画面描画で便利
    JSON との親和性

    View Slide

  7. GraphQL の採用例
    ▌Facebook
    ⚫ https://developers.facebook.com/docs/graph-api/
    ▌GitHub API v4
    ⚫ https://developer.github.com/v4/
    ▌AWS AppSync
    ⚫ https://aws.amazon.com/appsync/
    ▌Kibela
    ⚫ https://github.com/kibela/kibela-api-v1-document

    View Slide

  8. スキーマの書き方

    View Slide

  9. スキーマ定義言語(SDL)
    ▌データ型と操作の型を定義する
    ▌データ型の種別
    ⚫ Scalars(Int, String, Float, Boolean, ID, カスタム)
    ⚫ Enum
    ⚫ List
    ⚫ Objects / Input types
    ▌すべての型は nullable
    ⚫ Non-null な場合「String!」のように ! をつける

    View Slide

  10. Objects
    ▌各フィールドは実質的にメソッドの定義
    ⚫ 引数が持てる
    enum Instrument {
    PIANO
    FLUTE
    }
    type Person {
    name: String!
    age: Int!
    friends: [Person!]
    canPlay(inst: Instrument!): Boolean!
    }

    View Slide

  11. Input types
    ▌クエリで渡せる値はスカラ・Enum・もしくはイン
    プット型のみ
    ▌インプット型のフィールドは引数を持たない
    input SearchCondition {
    names: [String!]
    minAge: Int
    }
    type Query {
    searchPerson(cond: SearchCondition!) [Person!]!
    }

    View Slide

  12. Objects vs Input types
    ▌Objects の各フィールドはサーバーサイド処理の宣言
    ⚫ 各フィールドは値を返す resolver として実装
    ▌Input types は単なるデータフォーマット
    ⚫ JSON へのシリアライズ・デシリアライズを実装
    ⚫ custom scalar も同じ

    View Slide

  13. Root types
    ▌スキーマは、可能な操作を列挙する必要がある
    ▌それぞれ Query, Mutation, Subscription という type
    のオブジェクトで指定する
    type Query {
    searchPerson(cond: SearchCondition!) [Person!]!
    }
    type Mutation {
    addPerson(name: String!, age: Int!) Person!
    declareFriend(p1: String!, p2: String!) Bool!
    }

    View Slide

  14. ドキュメント
    ▌スキーマの各要素の前に説明を文字列で書ける
    ▌文字列は markdown で書ける
    ”””
    Person represents a **human** being.
    ”””
    type Person {
    name: String!
    age: Int!
    friends: [Person!]
    canPlay(inst: Instrument!): Boolean!
    }

    View Slide

  15. クエリの書き方

    View Slide

  16. GraphQL クエリとは
    ▌Query や Mutation を呼び出す書式
    ▌一度に複数呼び出すこともできる(Aliases)
    ▌クエリ自体を関数化することもできる
    ▌受け取るオブジェクトのフィールドは必ず指定が必要
    ⚫ SELECT * はできない

    View Slide

  17. Simplified Query
    {
    searchPerson(cond: {minAge: 30}) {
    name
    age
    friends {
    name
    friends {
    name
    }
    }
    }
    }

    View Slide

  18. Non-simplified Query
    query Search {
    searchPerson(cond: {minAge: 30}) {
    name
    age
    }
    }

    View Slide

  19. Multiple queries
    query MultiSearch {
    over30: searchPerson(cond: {minAge: 30}) {
    name
    age
    }
    mitz: searchPerson(cond: {names: [”mitz”]}) {
    name
    age
    }
    }

    View Slide

  20. Variables
    ▌Query のパラメーターを $var で変数化できる
    ▌変数は別途 JSON で与えられる
    query Search($cond: SearchCondition!) {
    searchPerson(cond: $cond) {
    name
    age
    }
    }
    ---
    {
    ”cond”: {”age”: 30}
    }

    View Slide

  21. 任意のキーバリューはどう扱うの?

    View Slide

  22. name/value ペアのリストで扱う
    type Label {
    name: String!
    value: String!
    }
    type Person {
    name: String!
    labels: [Label!]!
    }

    View Slide

  23. GraphQL サーバーの実装

    View Slide

  24. サーバー実装
    ▌各言語に多数のライブラリが存在
    ⚫ https://graphql.org/code/#server-libraries
    ▌Schema First 開発に向いていそうなもの
    ⚫ Node: Apollo
    ⚫ Go: gqlgen
    ⚫ Java: GraphQL Java Tools
    ⚫ PHP: Siler

    View Slide

  25. gqlgen
    ▌スキーマから Go のコードを自動生成
    ▌自動で生成できなかったレゾルバだけ実装すれば動く
    ▌生成例
    ⚫ https://github.com/ymmt2005/graphql-example

    View Slide

  26. GraphiQL でクエリを楽々開発

    View Slide

  27. GraphiQL とは
    ▌https://github.com/graphql/graphiql
    ▌JavaScript 製の GraphQL クエリ開発 IDE
    ▌gqlgen 等にも簡単に組み込める
    ▌Let’s try!
    ⚫ go run github.com/ymmt2005/graphql-example/server
    ⚫ http://localhost:8080/ にアクセス
    ⚫ ここまでに出てきたクエリを入力してみよう!

    View Slide

  28. sabakan / CKE 連携の実装例

    View Slide

  29. sabakan と CKE の関係
    ▌sabakan
    ⚫ 物理サーバーの情報を一元管理
    ⚫ ネットブート機能もある
    ▌CKE
    ⚫ Kubernetes クラスタを自動構築
    ⚫ 利用する物理サーバーの情報は外部から提供
    ▌CKE -> sabakan
    ⚫ CKE が sabakan に利用可能機材を問い合わせ
    ⚫ 機材の条件を人間が指定したい

    View Slide

  30. GraphQL を利用
    ▌sabakan
    ⚫ GraphQL API を実装
    ⚫ 機材を複雑な条件で検索可能にした
    ▌CKE
    ⚫ GraphQL クライアントを実装
    ⚫ クエリは固定
    ⚫ 検索条件は変数化
    ⚫ 人間は検索条件を JSON で指定可能

    View Slide

  31. クライアントの試験
    ▌CKE の単体テストで sabakan 連携をテストしたい
    ▌スキーマから自動生成したモックサーバーでテスト
    ⚫ Resolver で適当なものを返すだけ!
    ⚫ https://github.com/cybozu-go/cke/tree/master/sabakan/mock

    View Slide

  32. GraphQL vs OpenAPI vs gRPC

    View Slide

  33. OpenAPI とは
    ▌REST API 用のスキーマ
    ⚫ 旧 swagger
    ⚫ YAML/JSON で書く
    ▌見てのとおり、複雑
    openapi: "3.0.0"
    info:
    title: Simple API overview
    version: 2.0.0
    paths:
    /:
    get:
    operationId: listVersionsv2
    summary: List API versions
    responses:
    '200':
    description: |-
    200 response
    content:
    application/json:
    examples:
    foo:
    value: {
    "versions": [
    {
    "status": "CURRENT",
    "updated": "2011-01-21T11:33:21Z",
    "id": "v2.0",
    "links": [
    {
    "href": "http://127.0.0.1:8774/v2/",
    "rel": "self"
    }
    ]
    },
    {
    "status": "EXPERIMENTAL",
    "updated": "2013-07-23T11:33:21Z",
    "id": "v3.0",
    "links": [
    {
    "href": "http://127.0.0.1:8774/v3/",
    "rel": "self"
    }
    ]
    }
    ]
    }
    '300':
    description: |-
    300 response
    content:
    application/json:
    examples:
    foo:
    https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/api-with-examples.yaml

    View Slide

  34. 比較表
    GraphQL OpenAPI gRPC
    スキーマファースト Yes! 不可能ではない Yes!
    スキーマが書きやすい Yes! No Yes!
    クエリが手書きできる Yes! No (curl?) No
    ストリーミング サーバーのみ No 双方向
    成熟している No Yes? Yes
    BLOB No (拡張はある) Yes No
    IDE GraphiQL 等 swagger-editor 等 RPC なので不要
    ブラウザからの利用 Yes Yes gRPC-Web が必要
    Versioning 普通しない 普通する 普通しない
    性能 ひとつのクエリにまとめ
    る最適化ができる
    やり方次第 やり方次第

    View Slide

  35. 個人的所見
    ▌GraphQL は Query にとどめるのが無難
    ⚫ Mutation の応答内容をクエリ書式でかける柔軟性は多くの
    場合不要なので、単に実装コストが高くつく
    ▌OpenAPI はコードファーストでスキーマ自動生成が楽
    ⚫ Kubernetes API 方式
    ⚫ https://www.blazemeter.com/blog/how-to-generate-openapi-definitions-from-code/
    ▌gRPC が総合的に楽なので、なるべく使う
    ⚫ BLOB については REST を併用

    View Slide