はじめに
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":{}}'
# \ はコマンドの途中で改行していること表す
公式チュートリアルによれば、GET
メソッドを利用しても良いようだが、今回利用しているAPIでは、GETリクエストはできなかった。他のAPIでは、POST
×クエリパラメータで要求できたものもあった。
APIの定義次第なのかも。
【比較対象】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では、左の「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
を指定して、id
とdetails
を取得する要求電文を作ると
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
変数に取得した結果が入る。
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個しか使えない。
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-server
やNexus
を利用して、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は学習コストがそこそこ高そう。