GatsbyJSでのGraphQLの使い方

本文書は公開済みの”基礎から始めるGatsbyJS入門”の続きです。前回の文書でGatsbyのインストールやページの遷移、、コンポーネント作成、レイアウト、CSSの設定の確認を行いました。本文書ではGraphQLなど読者のみなさんがまだ学習した経験がないまたは馴染みのない技術も出てきますのでぜひこの機会にGatsbyだけではなくGraphQLがどのようなものかどのように利用されるのかということも合わせて理解してください。
目次
GraphQLの使い方
GraphQLとは
GraphQLはREST APIよりも効率的にデータを取得できる新しいAPIです。REST APIでは1つのEndpoint(URL)から得られるデータが十分ではない場合、それぞれのデータが取得できる複数のEndpoint(URL)に対して複数のAPIのリクエストを送信する必要があります。しかし、GraphQLでは1つのEndpoint(URL)に対して1度のリクエスト(GraphQL Query)で必要な情報を一括で取得することができます。
Gatsbyを使うことで外部のサーバからの情報取得だけではなくGatsby自体からデータを取得することができるのでGraphQLのQueryをどのように記述するのかを理解することができます。しかしGatsbyでは前提の知識も特別な設定もなくGraphQLが利用できるためGraphQL自体の詳細な技術的な理解は深まりません。どのようにGraphQLを利用するのかはわかりますが、GraphQLがどのような仕組みで動作しているかなどは別途学習が必要です。
はじめてのGraphQL
GraphQLを利用することでGatsbyの設定ファイルの一つであるgatsby-config.jsファイルに記述したmetaデータを取得することできます。REST APIでは設定ファイルから情報を取得するということはなかったと思うので最初は少し不自然に感じるかもしれません。しかしGatsbyではGraphQLを利用してローカルファイルの中身を取得することができます。
Gatsbyサイトのインストール時にインストールディレクトリ直下に作成されるgatsby-config.jsを開いて下記のようにmetaデータを記述しましょう。siteMetadataオブジェクトの中に複数のプロパティと値を設定しています。プロパティについては任意の名前をつけることができます。

titleを使ってサイトのタイトルを記述することができるためタイトルの更新が必要になった場合もすべてのページに即座に反映させることができます。
module.exports = {
siteMetadata: {
title: "はじめてのGatsby Site",
author: "Reffect",
category: ["Laravel", "Vue.js", "React"],
user: { name: "John Doe", email: "john@example.com" },
},
/* Your site config here */
plugins: [],
}
about.jsにGraphQLを記述してgasby-config.jsファイルからmetaデータを取得します。下記の記述はpage queryと呼ばれ、index.js、about.jsのようにページの元となるpageコンポーネント内で利用することができます。queryの結果はdataから取得することができ、data.site.siteMadata.titleでgatsby-config.jsに記述した値を取り出すことができます。
import React from "react"
import Layout from "../components/layout"
import { graphql } from 'gatsby'
const About = ({ data }) => {
return (
<div>
<Layout>
<h2>{data.site.siteMetadata.title}</h2>
<h1>About page</h1>
</Layout>
</div>
)
}
export const query = graphql`
query {
site {
siteMetadata {
title
}
}
}
`
export default About
ブラウザで確認するとGraphQLから取得したtitleが表示されることを確認することができます。


なぜ{data}のように記述するのかわからない場合は下記のように引数をpropsに変更して、console.log(props)でpropsの内容を確認してください。dataはpropsの中のデータの一部でDestructuring(分割代入)を使っているので{data}としていることがわかります。
const About = props => {
console.log(props)
return (
<div>
<layout>
<h2>{props.data.site.siteMetadata.title}</h2>
<h1>About page</h1>
</layout>
</div>
)
}
コンソールログで確認できるデータの中にdataが含まれていることがわかります。またpropsにはdata以外にも様々な情報が含まれていることも確認できます。ここでは必要な情報がdataのみなので分割代入を利用して{data}と記述しています。

staticQueryの使い方
ページコンポーネント以外のコンポーネントではuseStaticQueryを利用してGrasphQLでデータを取得することができます。
ここではheader.jsファイルを利用してuseStaticQueryの動作確認を行います。useStaticQueryを利用する場合はuseStaticQueryをimportしないとエラーになります。また先ほどのPageQueryとはコードの記述場所が変わります。
import React from "react"
import { useStaticQuery, Link } from "gatsby"
const Header = () => {
const data = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
}
}
}
`
)
return (
<header>
<h2>{data.site.siteMetadata.title}</h2>
<nav>
<ul>
<li>
<Link to="/">top</Link>
</li>
<li>
<Link to="/about">about</Link>
</li>
</ul>
</nav>
</header>
)
}
export default Header
ブラウザで確認するとheader.js内で取得したtitleがヘッダー内に表示されていることが確認できます。上部に表示されている”はじめてのGatsby Site”はheader.jsのuserStaticQueryから取得したもので、中盤にある”はじめてのGatsby Site”はabout.jsのPage Queryで取得したものです。

ここまではGraphQLのqueryの中身については触れてきませんでした。gatsby-config.jsの他のプロパティを取得したい場合にどのようにして行うかを確認しながらqueryの中身を確認していきます。
GraphiQLの使い方
gatsby-config.jsの他のプロパティの値を取得したい場合の正しいqueryをどのように記述するのかをどうすれば知ることができるでしょうか。GraphiQL(※GraphQLではありません)を利用することで正しいqueryを確認することができます。GraphiQLは正しいGraphQLのqueryの構造やどのような情報が取得できるかを確認することができるツールです。
GraphiQLを利用するためには、ブラウザのURLにhttp://localhost:8000/___graphiqlを入れてアクセスします。graphiqlの前には_(アンダーバー)が3つ入ります。

アクセスを行うと下記の画面が表示されます。左側のExplorerを使ってどのような値を取得できるかを確認することができます。

GraphiQLの使い方は下記のように左側にqueryを記述して実行を行うとqueryの結果が右側に表示されます。queryの内容は先ほどのPageQueryの内容と同じものをコピー&ペーストしています。右矢印の実行ボタンを押すと右側にtitleの内容が表示されていることが確認できます。


title以外の別のプロパティを取得するためにtitleの下に何か文字を入力すると入力支援で別のプロパティの候補が表示されるので入力の間違いもなく簡単に別のプロパティ情報を見つけることができます。

入力支援を使うことでgatsby-config.jsファイルのすべてのプロパティの情報を取得できるqueryを確認することができます。gatsby-config.jsに設定した文字列だけではなく配列やオブジェクトもqueryを使って取得できていることが確認できます。

ここまでの動作確認でGraphQLを利用してgatsby-config.jsファイルのメタタグの情報が取得できるようになりました。
ファイルシステムの情報取得
gatsby-config.jsファイルにGatsbyからアクセスすることができましたがその他のページファイルを含めたローカルのファイルシステムにGatsbyのアプリケーションからアクセスするためにはプラグインのインストールが必要になります。
インストールを行うプラグインはgatsby-source-filesystemです。プラグインはGatsbyの公式ホームページ上から確認することができます。Gatsbyの公式ホームページを開いて上部にあるメニューのPlugins(赤い四角)をクリックしてください。

左側のコラムに表示されるgatsby-source-filesystemをクリックしてください。もし表示されていない場合はSearch Gatsby Libararyの検索バーにsourceなどの文字列を入れると検索できます。

プラグインの名前をクリックするとインストール、プラグインの方法が記述されているのでその手順にしたがってインストールと設定を行います。

gatsbyインストールディレクトリでnpmコマンドを使ってgatsby-source-filesystemプラグインのインストールを行います。
% npm install --save gatsby-source-filesystem
インストールしたプラグインは先ほどメタタグを追加したgatsby-config.jsにプラグイン情報を追加する必要があります。
インストールしたgatsby-source-filesystemをgatsby-config.jsファイルに設定する前に設定前後でどのような変化があるのかGraphiQLを利用して確認しておきます。
設定前では全ファイル数を取得するallFileのtotalCountをqueryを実行してもファイルシステムにGatsbyからアクセスできないため0と表示されます。

gatsby-source-filesystemをインストールしただけではGatsbyからローカルファイルの情報にアクセスできないことがわかりました。
Gatsbyのインストールディレクトリ直下のsrc以下のファイルにアクセスできるようにgatsby-config.jsに下記の設定を行います。この設定を行うことでsrc以下のファイルへのアクセスが可能となります。
/* Your site config here */
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `src`,
path: `${__dirname}/src/`,
},
},
],
gatsby-config.jsを変更したのでgatsby developコマンドを一度停止、再度実行します。その後、先ほど実行したtotalCountを取得するGraphQLのqueryを実行します。設定後はtotalCount数が0から6に増えていることが確認できます。

なぜtotalCountを取得するqueryがわかるのかと不思議になる人もいるかと思います。ここまで説明をしていませんでしたが、Explorerボタンをクリックするとどのようなqueryがあるのかを確認することができます。後ほどファイルの情報を取得しますが、この時にもExplorerが役に立ちます。ファイルの情報を取得するためにはallFileを利用します。allFileの下にtotalCountを見つけることができます。

現在のsrcディレクトリ内のファイル数totalCount は、現在のフォルダ構成を確認しても6つのファイルが存在することが確認できます。

Explorerを参考にtotalCountだけではなくファイル名やサイズなどの情報も取得してみましょう。相対パスやファイルサイズ、名前や拡張子などさまざまな情報を取得できることがわかります。

ここまでの動作確認でローカルのファイルの情報をGraphQLを利用して取得できることがわかったので取得したデータをブラウザ上に表示させる方法を確認してみましょう。
Gatsbyのファイル内で記述するqueryのコードはGraphiQLのCode Exporterをクリックすることで確認することができます。GraphiQLではどのような情報が取得できるか確認できる上、実際にコードに記述するQueryも確認することができます。

about.jsファイルの中にファイル情報取得のGraphQLコードを記述します。about.jsファイルはページファイルなのでPage Queryを利用します。Code Expoterのコードをコピー&ペーストすることができます。
import React from "react"
import Layout from "../components/layout"
import { graphql } from 'gatsby'
const About = ({ data }) => {
console.log(data)
return (
<div>
<Layout>
<h1>About page</h1>
</Layout>
</div>
)
}
export const query = graphql`
{
allFile {
totalCount
nodes {
relativePath
size
name
extension
ctime
}
}
}
`
export default About
console.logでdataの中身を確認するとファイル情報が取得できていることが確認できます。

dataの中身を確認できたのでReactに慣れている人であればmap関数を利用して展開できることがわかります。map関数を利用して取得したデータをtableタグでブラウザの画面上に表示してみましょう。
import React from "react"
import Layout from "../components/layout"
import { graphql } from "gatsby"
const About = ({ data }) => {
console.log(data)
return (
<div>
<Layout>
<h1>About page</h1>
<table>
<thead>
<tr>
<th>パス</th>
<th>サイズ</th>
<th>作成時間</th>
</tr>
</thead>
<tbody>
{data.allFile.nodes.map(node => (
<tr>
<td>{node.relativePath}</td>
<td>{node.size}</td>
<td>{node.ctime}</td>
</tr>
))}
</tbody>
</table>
</Layout>
</div>
)
}
export const query = graphql`
{
allFile {
totalCount
nodes {
relativePath
size
name
extension
ctime
}
}
}
`
export default About
ブラウザで確認すると下記のようにGraphQLで取得したデータを表示させることができます。

GraphQLを利用して内部のファイル情報を取得し、map関数で展開しブラウザで表示することができるようになりました。少しずつですが、GraphQLの使い方の理解が深まっているのではないでしょうか。
Markdownファイルからの読み込み
これまでの説明でファイルのパスやサイズなどの情報を取得する方法がわかりました。しかし、ファイル情報だけでなくファイルの中身も取得したいものです。GatsbyからGraphQLを利用してMarkdown(マークダウン)ファイルへアクセスしファイルの中身が取得できることを確認していきます。
Markdown(マークダウン)の中身を取得することでできれば文字だけのブログサイトを構築することが可能です。画像の取得はまた別の機能が必要となるので後ほど説明を行います。
Markdown(マークダウン)とは
WEBページを作成する際、通常はHTMLで記述します。HTMLでWEBページを作成するためにはタグを理解する必要があり使いこなすまでに時間が必要となります。しかしMarkdownではタグの変わりにシンプルなSyntax(シンタックス)を利用するので読みやすく軽量のためHTMLと比較すると使いこなすまでの時間があまりかかりません。一般的なユーザにMarkdownを覚えてもらうことは難しいですがエンジニアであれば覚えることはそれほど難しくありません。また作成したMarkdownで記述したファイルはパーサーによりHTMLに変換を行うことができます。ブログの記事やGithub, Qiita, Zennなどでも利用されており、ファイルの拡張子はmdです。
本文書についてはMarkdownの記述方法についての細かな説明を行いませんが、Markdownの記述方法を知らなくても今後説明する内容への影響はありません。
Markdownファイルの作成
Markdownファイルを保存するディレクトリpostsをsrcディレクトリの下に作成します。
ファイル名をfirst-article.mdとし、ファイルの先頭にはメタデータを記述するFront Matter(フロントマター)を記述します。titleとdateを記述していますがプロパティと値のペアであればなんでも追加することができます。
Front Matterは3つのハイフンで囲みます。###は見出しの設定を行っておりh3タグを意味します。見出しの下に2行の文を追加します。2行の間に1行空白行を入れることで改行を行うhtmlに変換するpタグが別々に設定されます。###や空白の情報をmdからHTMLへの変換時にパーサーが理解し、タグのないMarkdownのテキスト文書をHTMLへ変換します。
---
title: 'はじめての記事'
date: '2022-10-05'
---
### Gatsby での最初の記事
Gatsby サイト上に表示するための初めての記事です。
ブラウザ上に表示されるのか確認です。
プラグインのインストール
mdファイルを作成しましたが、ここまでの設定ではGatsbyからファイルの中身を確認することができません。mdファイルの内容を取得してブラウザ上に表示させるためにはHTMLに変換をする必要があります。そのためには新たにプラグインをインストールする必要があります。
インストールするプラグインは、gatsby-transfermer-remarkです。GatsbyサイトのPluginでremarkと入力すると表示されます。

表示される手順に従ってプラグインのインストールを行います。
% npm install gatsby-transformer-remark
インストールしたプラグインはgatsby-config.jsに追加する必要があります。
module.exports = {
siteMetadata: {
//略
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `src`,
path: `${__dirname}/src/`,
},
},
'gatsby-transformer-remark',
],
};

GraphiQLにアクセスしてExplorerを表示するとallMarkdownRemarkとmarkdownRemarkが追加されていることを確認することができます。この2つを利用することでMarkdownファイルにアクセスすることができます。

Markdownファイルの内容取得
追加されたallMarkdownRemarkを利用してmdファイルの内容を確認していきます。Explorerを確認しながらfrontmatterでtitleとdate、htmlで内容、文字数から文書を読む時間を算出したtimeToReadの値を取得します。


mdファイルの内容を取得するためのGraphQLのqueryがわかったのでCode Exporterを確認してQueryをindex.jsファイルに設定を行います。
import React from "react"
import Layout from "../components/layout"
import { graphql } from "gatsby"
export default function Home({ data }) {
return (
<div>
<Layout>
<h1>Gatsby Blog Site</h1>
{data.allMarkdownRemark.nodes.map(node => (
<div key={node.id}>
<h2>{node.frontmatter.title}</h2>
<p>{node.frontmatter.date}</p>
<div dangerouslySetInnerHTML={{ __html: node.html }} />
</div>
))}
</Layout>
</div>
)
}
export const query = graphql`
{
allMarkdownRemark {
nodes {
id
html
timeToRead
frontmatter {
date
title
}
}
}
}
`
ブラウザで確認を行うとCSSの設定を行っていないのでわかりにくいかもしれませんが、title, dateとhtmlの内容がすべてブラウザ上に表示されていることが確認できます。mdファイルに指定したシンタック###(h3)やpタグの設定が反映されていることがわかります。

1つの記事しか作成していなかったのでもう一つ追加でmdファイルを作成します。作成場所はpostsディレクトリの下でファイル名はsecond-article.mdとしています。
allMarkdownRemarkはすべてのmdファイルの情報を取得しているので、記事を作成するとコードの変更なしで追加したmdファイルの内容が表示されます。

ここまでの説明でGraphQLを利用してローカルファイルへのアクセス、mdファイルの内容を取得できるようになり、GatsbyにおけるGraphQLの使い方と取得後のデータの処理について学ぶことができました。