初めてのGraphQLとApollo ServerとVue.js

GraphQLをクライアント側で使用した経験または単語は耳にしたことはあるが実際にGraphQLのサーバ側ではどのような設定が行われているか知らない人も多いかと思います。
本文書ではGraphQLのQueryの記述方法ではなく、GraphQLサーバ側ではどのような処理が必要なのかまたクライアントはどのようなコードでGraphQLサーバにアクセスしなければならないかの説明を行っています。vue.js上でfetchを利用してGraphQLからのデータ取得も確認しています。
動作確認にはGraphQLのサーバが構築できるオープンソースのApollo Serverを利用しています。Apollo ServerはJavaScriptのライブラリなのでJavaScriptの知識が必要となります。また環境を構築する際はNode.jsをインストールしておく必要があります。
目次
プロジェクトの作成
Apollo Server用の任意のディレクトリを作成してください。
% mkdir graphql-server-example
% cd graphql-server-example
package.jsonファイルを作成するためにnpm init -yコマンドを実行します。実行するとディレクトリ内にpackage.jsonファイルが作成されます。
% npm init -y
% ls
package.json
ライブラリのインストール
Apollo Serverには2つのライブラリが必要となります。
- apollo-server
- graphql
npmコマンドを使ってインストールを行います。
% npm install apollo-server graphql
インストールが完了したら、index.jsファイルを作成してください。index.jsファイルにApollo Serverに必要なコードを記述していきます。
% touch index.js

スキーマの定義
index.jsファイルを開いて、apollo-serverからapollo serverに必要なモジュールをrequireします。
const { ApolloServer, gql } = require('apollo-server');

通常はスキーマを定義してデータを作成することになりますが、スキーマがどのように構成されているかわかりやすいように先にサンプルデータを作成しindex.jsファイルに記述します。title, authorで構成されています。
const { ApolloServer, gql } = require('apollo-server');
const books = [
{
title: 'Harry Potter and the Chamber of Secrets',
author: 'J.K. Rowling',
},
{
title: 'Jurassic Park',
author: 'Michael Crichton',
},
];
先にデータを作成したのでクライアントからアクセスするデータの構造はtitle, authorで構成されているので下記のように記述を行うことができます。titleとauthorには文字列が入っているのでデータの型はStringとなります。
type Book {
title: String
author: String
}
スキーマについてはindex.jsにそのまま記述するのではなくgqlの中に記述します。
const typeDefs = gql`
type Book {
title: String
author: String
}
`
次にQueryタイプを設定します。QueryタイプはクライアントがGraphQLを利用してアクセスする際に利用します。queryでbooksを指定して実行するとBookタイプの配列がクライアントに戻されることになります。booksはBookタイプの配列であることを宣言しています。何もデータがない時は空の配列が戻されます。Queryタイプは必ず設定を行う必要があり、Queryタイプの中にクライアントが利用するqueryを追加していくことになります。
const typeDefs = gql`
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
Resolverの設定
サンプルデータとスキーマの設定は行いましたが、アクセスがあった場合はどのようなデータを戻すかが設定されていません。その設定を行うのがResolverです。ResolverのQueryの中でbooksと指定していますが、これがスキーマのQueryタイプの中で定義したbooksです。クライアントからのqueryでbooksが指定された場合はbooksプロパティの値である関数が実行されます。関数を使うことでどのようなデータをクライアントに戻すのか制御することができます。
const resolvers = {
Query: {
books: () => books,
},
};
Apollo Serverの設定
サンプルデータ、スキーマ、Resolverの設定が完了したので、Apolloサーバの設定を行います。
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});

設定が完了したのでサーバの起動を行います。ポート4000で起動することがわかります。
% node index.js
🚀 Server ready at http://localhost:4000/
ブラウザからのアクセス
ブラウザで http://localhost:4000/にアクセスすると下記の画面が表示されます。GraphQL Playgroundと呼ばれるツールでこの画面からGraphQLを実行しAppoloサーバからデータを取得することができます。

画面の左側にQueryを記述し真ん中にあるプレイボタンをクリックすると実行され右側に実行結果が表示されます。
“# Write your query or mutation here”と表示されている場所にQueryを記述します。

GraphQueryの実行
GraphQL Playgroundを使ってGraphQLのQueryを実行します。GraphQL Playgroundはアルファベットのキーを入力するだけで候補が表示されるので簡単にQueryを作成することができます。queryの中にbooksを取得しbooksの中から取得したデータを記述します。Bookタイプはtitleとauthorで構成しているのでtitileとauthorを指定しています。どちらかの指定でもかまいません。


真ん中にあるプレイボタンをクリックするとQueryが実行され結果が右側に表示されます。index.jsに記述したサンプルデータの中身と同じことがわかります。

Apollo Serverを使うことによって簡単にGraphQLを実行する環境を作成することができました。
しかしここで一つの疑問が浮かびます。クライアントからアクセスする際にはGraphQL Playgroundを利用することはできません。どのようにクライアントがGraphQLのデータにアクセスするのでしょう。その方法について確認していきます。
fetchによるGraphQLサーバからデータ取得
クライアントからGraphQLへのアクセスにはGraphQL Clientがありますが、ここではfetchを利用します。
fetchを利用してGraphQLにアクセスを行いデータが取得できるか確認を行います。
fetchを使ってデータを取得するためにhtmlファイルを作成し、scriptタグにfetchを利用したコードを記述します。
<!DOCTYPE html>
<html lang="ja"">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h1>Fetchを利用したGraphQLへのアクセス</h1>
</body>
<script>
async function fetchBooks() {
const response = await fetch("http://localhost:4000", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `query{
books{
title
author
}
}`,
}),
});
const data = await response.json();
console.log(data);
}
fetchBooks();
</script>
</html>
fetchを利用してGraphQLにアクセスする場合のポイントがいくつかあります。
- メソッドにはPOSTを利用
- bodyにGraphQLのqueryを記述しJSONに変換
- headersにはContent-Typeのapplication/jsonを指定
console.logの内容を確認するとサンプルデータの内容が表示されていることが確認できます。

GraphQLのClientを利用しなくてもGraphQLサーバからfetchを利用してデータが取得できることが確認できました。
Vue.jsを使って取得したデータを描写
fetchでデータが取得できるということはvue.jsを利用してもデータを取得できることなのでcdnのvue.jsを利用して取得したデータを描写してみましょう。fetchの内容は変わっていませんが、取得したデータをデータプロパティのbooksに保存して、v-forで展開を行っています。
<!DOCTYPE html>
<html lang="ja"">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h1>Fetchを利用したGraphQLへのアクセス</h1>
<div id="app">
<ul>
<li v-for="(book,index) in books" :key="book">{{ book.title }}/{{ book.author }}</li>
</ul>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script>
new Vue({
el: "#app",
data:{
books:[]
},
methods:{
async fetchBooks() {
const response = await fetch("http://localhost:4000", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `query{
books{
title
author
}
}`,
}),
});
const { data } = await response.json()
return data;
}
},
mounted(){
this.fetchBooks().then(({books}) => this.books = books);
}
})
</script>
</html>
ブラウザでidex.htmlファイルを確認するとGraphQLに保存したサンプルデータが表示されることを確認できます。

vue.jsでもfetchを利用することでGraphQLからデータが取得できることが確認できました。
非常にシンプルなサンプルデータとスキーマ構造でしたが、Apollo Severの設定方法とGraphQLを利用したデータの取得方法を確認することができました。