LoginSignup
5
3

More than 3 years have passed since last update.

GraphQL(クエリ言語について)

Posted at

はじめに

GraphQLをざっくり理解するためにやったことをまとめときます。
GraphQLとはなんなのか的なことは、こちらの記事に丸投げします。肩がねじ切れんばかりに投げてますが、自分はクエリ言語(フロント側、リクエスト)とスキーマ言語(サーバー側、レスポンス)に分けて写経などをしました。
RestAPIだと処理ごとにエンドポイントがありましたが、GraphQLではエンドポイントは1つです。GraphQLは、サーバー側で何かをする関数を用意しておき、その関数をフロント側で実行するイメージで理解しています。

今回はクエリ言語のみまとめます。

クエリ言語

クエリ言語は、GraphQL APIのリクエストのための言語で、これはさらにデータ取得系のquery、データ更新系のmutation、サーバーサイドからのイベントの通知であるsubscriptionの3種類があります。

はい、クエリ言語とはこういうことです。右肩が痛いですね。今回はsubscriptionについては触れませんが、ざっくりと説明するとsubscriptionは、サーバー側の変更をクライアント側でホットリロードするような時に使うみたいです。

query、mutation、paginationをGraphQL Explorer(GithubのGraphQL API)で試していきます。paginationは、サーバーが一度に全てではなく、小さなチャンクに分けてデータを送信できる仕組みです。
こちらの記事を参考にしました。(GraphQLをReactで扱う方法もあり、分かりやすいです。)

query

データの取得をする。(データの読み取り)

基本

// クエリ
query {
  viewer{ // GithubのGraphQL API
    name
    url
  }
}

// レスポンス
{
  "data": {
    "viewer": {
      "name": "kirisawa",
      "url": "https://github.com/kirikirisu"
    }
  }
}

・viewerをオブジェクトという。
・nameやurlをフィールドと言い、オブジェクトの特定のプロパティを要求するために使用される。
・クエリは単なるオブジェクトとフィールド、オブジェクトはフィールドとも呼ぶ。
・オブジェクトはサーバ側で"スキーマ"で定義されており、定義されているものをDocから確認できる。(後から出てくるMutationも)

フィールド(オブジェクト)に引数を渡す

// クエリ
query {
  organization(login: "the-road-to-learn-react"){
    name
    url
  }
}

// レスポンス
{
  "data": {
    "organization": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react"
    }
  }
}

・organizationフィールドに公開されいるorganization名を渡す。
・引数はstringだけでなく、numberやbooleanなどを渡す場合もある。
・フィールドレベルでリクエストを指定できるため、クエリの柔軟性が高い。

2つ以上の同一オブジェクトにデータを要求する

・2つ以上の同一のオブジェクトにデータを要求するには決まったエイリアスを使う。

// クエリ
// これは失敗する
query {
  organization(login: "the-road-to-learn-react") {
    name
    url
  }
  organization(login: "facebook") {
    name
    url
  }
}

// こうする
query {
  book: organization(login: "the-road-to-learn-react") {
    name
    url
  }
  company:organization(login: "facebook") {
    name
    url
  }
}

// レスポンス
{
  "data": {
    "book": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react"
    },
    "company": {
      "name": "Facebook",
      "url": "https://github.com/facebook"
    }
  }
}

フィールドの共通化

・フラグメントを使用し、フィールドの再利用できる部分を抽出する。

// クエリ
query {
  book: organization(login: "the-road-to-learn-react") {
    ...sharedOrganizationFields
  }
  company: organization(login: "facebook") {
    ...sharedOrganizationFields
  }
}

fragment sharedOrganizationFields on Organization {
  name
  url
}

// レスポンス
{
  "data": {
    "book": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react"
    },
    "company": {
      "name": "Facebook",
      "url": "https://github.com/facebook"
    }
  }
}

・「on Organization」は、GithubのGraphQL APIによって定義されたオブジェクトのタイプ。TypeScriptでの型定義のようなもの。

変数を使う

・"Query Variables"から変数を提供する。
・変数を使うことで動的にクエリを作ることができる。
・$ 記号で引数を変数として定義する。
・ ! はその引数が必須であることを示す。ない場合は必須ではない。

// クエリ
query ($organization: String!) {
  organization(login: $organization) {
    name
    url
  }
}

// Query Variables
{
  "organization": "the-road-to-learn-react"
}

// レスポンス
{
  "data": {
    "organization": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react"
    }
  }
}

クエリに名前をつける

・JavaScript無名関数と名前付き関数に似ている。
・付けた名前は、「オペレーションタイプ」や「オペレーションネーム」と言われる。

// 名前なし
query {
  organization(login: "the-road-to-learn-react") {
    name
    url
  }
}

// 名前あり
query OrganizationForLearningReact {
  organization(login: "the-road-to-learn-react") {
    name
    url
  }
}

// 名前あり、引数あり
query OrganizationForLearningReact($organization: String!) {
  organization(login: $organization) {
    name
    url
  }
}

// レスポンスは同じ

ネストされたオブジェクトにアクセスする

・ネストされたオブジェクトにアクセスするためには、クエリもネストするだけ。

// クエリ
query OrganizationForLearningReact(
  $organization: String!,
  $repository: String!
) {
  organization(login: $organization) {
    name
    url
    repository(name: $repository) {
      name
    }
  }
}

// Query Variables
{
  "organization": "the-road-to-learn-react",
  "repository": "the-road-to-learn-react-chinese"
}

ディレクティブ

@include,@skipによって特定のフィールドを取得したり、取得しなかったりできる。
@includeは、ifで評価する変数が true の時、フィールドを取得する。(falseの時取得しない)
@skipは、falseの時フィールドを取得する。(trueの時取得しない)

// クエリ
query OrganizationForLearningReact(
  $organization: String!,
  $repository: String!,
  $withFork: Boolean!
) {
  organization(login: $organization) {
    name
    url
    repository(name: $repository) {
      name
      forkCount @include(if: $withFork)
    }
  }
}

// Query Variables
{
  "organization": "the-road-to-learn-react",
  "repository": "the-road-to-learn-react-chinese",
  "withFork": true
}

mutation

GraphQL APIから提供され、何かを実行する。(データの書き込み)

・Githubのリポジトリにスターをつけるmutation。

// まずクエリによってリポジトリのidを取得する
query {
  organization(login: "the-road-to-learn-react") {
    name
    url
    repository(name: "the-road-to-learn-react") {
      id
      name
    }
  }
}
// レスポンス
{
  "data": {
    "organization": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react",
      "repository": {
        "id": "MDEwOlJlcG9zaXRvcnk2MzM1MjkwNw==",
        "name": "the-road-to-learn-react"
      }
    }
  }
}

// そしてミューテーションによってリポジトリにスターをつける
mutation AddStar ($repositoryId: ID!) {
  addStar(input: { starrableId: $repositoryId }){
    starrable {
      id
      viewerHasStarred
    }
  }
}
// Query Variables
{
  "repositoryId": "MDEwOlJlcG9zaXRvcnk2MzM1MjkwNw=="
}

// レスポンス
{
  "data": {
    "addStar": {
      "starrable": {
        "id": "MDEwOlJlcG9zaXRvcnk2MzM1MjkwNw==",
        "viewerHasStarred": true
      }
    }
  }
}

・mutation(addStar)は、Github GraphQL APIから提供されている。
・上記は名前(AddStar)付きミューテーションで、名前は任意の名前をつける。
・クエリのようにオブジェクトとフィールドを使用して、ミューテーションの戻り値を指定できる。

// スターを消すミューテーション
mutation AddStar($repositoryId: ID!) {
  removeStar(input: { starrableId: $repositoryId }) {
    starrable {
      id
      viewerHasStarred
    }
  }
}

// レスポンス
{
  "data": {
    "removeStar": {
      "starrable": {
        "id": "MDEwOlJlcG9zaXRvcnk2MzM1MjkwNw==",
        "viewerHasStarred": false
      }
    }
  }
}

Pagination

大きなデータを複数に分けて取得する

リポジトリリストの中からふたつずつリポジトリを取得

query OrganizationForLearningReact {
  organization(login: "the-road-to-learn-react") {
    name
    url
    repositories(first: 2) {
      edges {
        node {
          name
        }
        cursor
      }
    }
  }
}

// レスポンス
{
  "data": {
    "organization": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react",
      "repositories": {
        "edges": [
          {
            "node": {
              "name": "the-road-to-learn-react"
            },
            "cursor": "Y3Vyc29yOnYyOpHOA8awSw=="
          },
          {
            "node": {
              "name": "hackernews-client"
            },
            "cursor": "Y3Vyc29yOnYyOpHOBGhimw=="
          }
        ]
      }
    }
  }
}

・ (first: 2)でリポジトリスト上から2つを指定。cursorは、そのリポジトリの位置情報。
・次に、取得した位置情報から2つのリポジトリを取得する。

query OrganizationForLearningReact {
  organization(login: "the-road-to-learn-react") {
    name
    url
    repositories(first: 2, after: "Y3Vyc29yOnYyOpHOA8awSw==") {
      edges {
        node {
          name
        }
        cursor
      }
    }
  }
}

// レスポンス
{
  "data": {
    "organization": {
      "name": "The Road to learn React",
      "url": "https://github.com/the-road-to-learn-react",
      "repositories": {
        "edges": [
          {
            "node": {
              "name": "hackernews-client"
            },
            "cursor": "Y3Vyc29yOnYyOpHOBGhimw=="
          },
          {
            "node": {
              "name": "react-local-storage"
            },
            "cursor": "Y3Vyc29yOnYyOpHOBUuT2A=="
          }
        ]
      }
    }
  }
}

最後に

最後まで読んでいただきありがとうございました。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3