GraphQLって何?

2022/2/20

(最終更新: 2022/2/20

アイキャッチ画像

はじめに

GraphQLとは、Facebookが開発した、REST-APIに変わるAPIの方式

GraphQLとは?を簡単にまとめる。

GraphQLの特徴

  • REST-JSONと違って、「必要なものを指定して」要求することができる。
  • 応答は普通のJSON形式。

RESTより優れている部分

  • 不要なデータが返却されない分、通信量が軽くなる。
  • 要求側で必要なものを指定するので、APIのエンドポイント(URL)を分ける必要性が低い。そのため、欲しい情報をすべて取りきるために何度もAPIを投げる必要が無くなる。

要求と応答

GraphQLの要求と応答例

GraphQLでは以下のように、取得したい項目を選んで要求をする。

# feed > idを取得したい
query {
  feed {
    id
  }
}

応答は以下のように返却される。

{
  "data": {
    "feed": [
      {
        "id": 1
      },
      {
        "id": 2
      }
    ]
  }
}

他にも情報が欲しい場合は、以下の要求のようにフィールドを追加する。

query {
  feed {
    id
    url
    description
  }
}

以下のように返ってくる。

{
  "data": {
    "feed": [
      {
        "id": 1,
        "url": "www.howtographql.com",
        "description": "1つめのリンク。"
      },
      {
        "id": 2,
        "url": "graphql.org",
        "description": "2つめのリンク。"
      }
    ]
  }
}

HTTPリクエスト方法

GraphQLは一般的にリクエストボディにクエリを詰め込んで要求する。

オープンソースAPIをたたいてみましょう。

https://api.spacex.land/graphql/

curl --location --request POST 'https://api.spacex.land/graphql/' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{ launchesPast(limit: 10) { mission_name rocket {rocket_name}}}","variables":{}}'
# \ はコマンドの途中で改行していること表す

Postmanを使った要求の仕方 Postmanを使った要求の仕方

公式チュートリアルによれば、GETメソッドを利用しても良いようだが、今回利用しているAPIでは、GETリクエストはできなかった。他のAPIでは、POST×クエリパラメータで要求できたものもあった。 APIの定義次第なのかも。

Serving over HTTP | GraphQL

【比較対象】REST-JSONの要求と応答例

一方で、REST-APIでは以下のようにエンドポイントを指定して要求する(または、クエリパラメータを用いる。)

# REST-APIの要求例(GET)
https://jsonplaceholder.typicode.com/posts/1

# 応答のbody部
{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}

例のように、「idが1である情報を全部ください」という場合は問題ないが、画面によっては、「全投稿の情報が欲しいけど、ユーザIDとタイトルだけでいい」などの要望が出てくる。

その場合、受け取る側は、タイトルや本文など使わない情報をたくさん受け取ることになってしまう。

Facebookでは、「友達の友達の友達の…」などの情報があるのでREST-JSONでは対応しきれなかったらしい。

要求電文に引数を指定する方法

GraphQLでは、結果絞り込みのための引数を設定することができる。 以下の記事に記載した。

GraphQLの引数を変数で設定する方法のメモ - エンジニアを目指す日常ブログ

要求電文の作り方(GraphQL APIの使い方)

APIの内部構造をわかった上で要求電文を書く必要がある。

要求電文には3つの方式(ルートタイプ)がある。

  • Query (照会)
  • Mutation (更新)
  • Subscription (データ検知してプッシュ)

一般公開されているGraph QLのAPIには、「GraphiQL」というツールを使って公開されているものがある。これを使うと、データ構造や条件式の必須などが視覚的にわかるので、簡単にリクエストを作成できる。

先ほど利用した、Facebookが作成している「Space-X」というAPIでもGraphiQLが公開されている。

https://api.spacex.land/graphql

GraphiQLの画面

  • GraphiQLでは、左の「Explorer」画面にチェックを入れていくと要求電文を作って結果を確認できる(結果が右側)
  • 一番右側のドキュメントには、フィールドの型が記載されている
  • (例)上記の画面から、historyフィールドの型がHistoryであることがわかる
  • (例)上記の画面から、historyフィールドはidが引数であることが確認できる。!がついている場合は必須となる。

History型は以下の型を含んでいる。

details: String
event_date_unix: Date
event_date_utc: Date
id: ID
links: Link
title: String
flight: Launch

ここから、idを指定して、iddetailsを取得する要求電文を作ると

query Query {
  history(id:2) {
    id
    details
  }
}

となる。

応答は

{
  "data": {
    "history": {
      "id": "2"
      "details": "NASA awards SpaceX $1.6B Commercial Resupply Services (CRS) contract.",
    }
  }
}

となる。

アプリでの使い方例

実際にGatsby.jsでGraphQL APIを使った例が以下。

Gatsby.jsの useStaticQueryを使った場合

const data = useStaticQuery(graphql`
// クエリ
`)

と記載することで、data変数に取得した結果が入る。

about.js
import { useStaticQuery, graphql } from 'gatsby';
import * as React from 'react'
import MyLayout from '../components/myLayout';

const About = () => {
    const data = useStaticQuery(graphql`
    query {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

    return (
        <MyLayout pageTitle="このサイトについて">
            <p>{data.site.siteMetadata.title}</p>
        </MyLayout>
    )

}

export default About;

Gatsby.jsのquery(ページクエリ)を使った場合

export const query = graphql`
// クエリ
`;

と記載すると、同じコンポーネントのpropsオブジェクトに自動的に値が入ってくる。

そのため

ページクエリは1コンポーネントにつき1個しか使えない。

index.js
import { graphql } from "gatsby";
import { MDXRenderer } from "gatsby-plugin-mdx";
import * as React from "react";
import MyLayout from "../components/myLayout";

const Index = (props) => {
    const { data } = props;    return (
        <MyLayout pageTitle="ブログ一覧">
            {data.allMdx.nodes.map((node) => (
                <article>
                    <h2>{node.frontmatter.title}</h2>
                    <p>Posted: {node.frontmatter.date}</p>
                    <MDXRenderer>
                        {node.body}
                    </MDXRenderer>
                </article>
            ))}
        </MyLayout>
    );
};

export const query = graphql`    query {        allMdx(sort: { fields: frontmatter___date }) {            nodes {                frontmatter {                    title                    date(formatString: "YYYY年MM月DD日")                }                id                body                parent {                    ... on File {                        modifiedTime                    }                }            }        }    }`;
export default Index;

参考:useStaticQueryとgraphqlどちらを使うか

おわりに

GraphQLはGatsbyにも利用されているので、理解したいが、かなり奥が深い。 Apollo-serverNexusを利用して、GraphQLのAPIを提供するWebサーバも作ってみようと思っているので、理解出来たら記事にしたい。

Building a GraphQL Server with TypeScript & Apollo

REST-JSONはExpressを使えば、

app.get("/", (req, res) => {
    res.status(200).send({ id: 1, message: "メッセージ" });
});

これだけでAPIを作れたのだが、GraphQLは学習コストがそこそこ高そう。



個別連絡はこちらへ→Twitterお問い合わせ

プロフィール

プロフィールイメージ

はち子

事業会社のシステム部門で働きはじめて5年目の会社員。システム企画/要件定義/システムアーキテクチャ等。

Twitter→@bun_sugi

過去の記事について

はてなブログに掲載の記事(主にプログラミングメモ)についてはこちらに掲載しております。(本ブログに移行中)

タグ一覧

関連記事

Copyright© 2023, エンジニアを目指す日常ブログ

お問い合わせ|プライバシーポリシー