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
touchコマンドを使うと空のファイルを作成することができます。

スキーマの定義

index.jsファイルを開いて、apollo-serverからapollo serverに必要なモジュールをrequireします。


const { ApolloServer, gql } = require('apollo-server');
ApploServerはサーバ、gqlはスキーマを定義する際に利用します。

通常はスキーマを定義してデータを作成することになりますが、スキーマがどのように構成されているかわかりやすいように先にサンプルデータを作成し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}`);
});
起動するポートを変更したい場合はlistenに引数にportプロパティ、値にポート番号を設定したオブジェクトを入れることで変更することができます。

設定が完了したのでサーバの起動を行います。ポート4000で起動することがわかります。


 % node index.js
🚀  Server ready at http://localhost:4000/

ブラウザからのアクセス

ブラウザで http://localhost:4000/にアクセスすると下記の画面が表示されます。GraphQL Playgroundと呼ばれるツールでこの画面からGraphQLを実行しAppoloサーバからデータを取得することができます。

GraphQL Playground
GraphQL Playground

画面の左側にQueryを記述し真ん中にあるプレイボタンをクリックすると実行され右側に実行結果が表示されます。

“# Write your query or mutation here”と表示されている場所にQueryを記述します。

GraphQLのQueryを記述する場所
GraphQLのQueryを記述する場所

GraphQueryの実行

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

はじめてのQuery
はじめてのQuery
ctrl + spaceキーでGraphQL Playground上で選択できる項目の候補が表示されます。

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

Queryの結果が表示
Queryの結果が表示

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の内容を確認するとサンプルデータの内容が表示されていることが確認できます。

fetchでGraphQLサーバからデータ取得
fetchでGraphQLサーバからデータ取得

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に保存したサンプルデータが表示されることを確認できます。

Apollo Serverから取得したデータをv-forで展開
Apollo Serverから取得したデータをv-forで展開

vue.jsでもfetchを利用することでGraphQLからデータが取得できることが確認できました。

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