Laravel5.8プロジェクトにてGraphQL使ってみた

# 概要

DockerやPHPの勉強にと作成したLaravelプロジェクトでGraphQLを使ってみました。
とりあえず動かせるようにしただけなので詳しい解説等は今後書ければと思いますので
一旦、備忘的なものです。

# やりたいこと
* LighthouseというPHPパッケージを用いてLaravel5.8上でGraphQLを使えるようにする
* React＋Apollo Clientを用いてフロントエンドに表示

# Lighthouseを用いてGraphQLを使えるようにする

Lighthouseは、LaravelアプリケーションからGraphQLエンドポイントを提供することを可能にするPHPパッケージです。
>Lighthouse is a PHP package that allows you to serve a GraphQL endpoint from your Laravel application. 

Lighthouse公式サイトにてインストール手順が公開されているのでそちらを参考に導入しました。
https://lighthouse-php.com/master/getting-started/installation.html#install-via-composer

```
Lighthouseパッケージのインストール/初期設定
$ composer require nuwave/lighthouse
$ php artisan vendor:publish --provider="Nuwave\Lighthouse\Providers\LighthouseServiceProvider" --tag=schema

動作チェックに使用するツールのインストール/初期設定
$ composer require mll-lab/laravel-graphql-playground
$ php artisan vendor:publish --provider="MLL\GraphQLPlayground\GraphQLPlaygroundServiceProvider"
```

http://localhost/graphql-playground にアクセスするとGraphQLを試すことできます。
↓こんな画面が表示されます
<img width="1435" alt="screenshot 2019-07-13 15.09.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/1f53fe82-1767-e213-81c9-16fd1874b68b.png">

ちなみに、上記手順でうまくいかなかった際にはlaravelプロジェクト直下に「graphql/schema.graphql」が作られているか確認してみてください。
もしなければ「vendor/nuwave/lighthouse/assets/default-schema.graphql」をコピーして該当ファイルを作成すると上手く動作するかもしれません。

以下はschema.graphqlの中身です。
Userデータの一覧取得およびID指定での取得用の設定がデフォルトで記述してあります。

```graphql/schema.graphql
"A datetime string with format `Y-m-d H:i:s`, e.g. `2018-01-01 13:00:00`."
scalar DateTime @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime")

"A date string with format `Y-m-d`, e.g. `2011-05-23`."
scalar Date @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date")

type Query {
    users: [User!]! @paginate(type: "paginator" model: "App\\User")
    user(id: ID @eq): User @find(model: "App\\User")
}

type User {
    id: ID!
    name: String!
    email: String!
    created_at: DateTime!
    updated_at: DateTime!
}

```

試しにid 2番のユーザーデータを取得してみます。
<img width="1436" alt="screenshot 2019-07-13 15.22.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/9be0caa1-82e0-93fe-99b0-2371c00bc31b.png">
現状ではtype Queryに設定されたusers、userクエリしかありません。
例えば新規userを作成しようと思ったら、type Mutationを追加しそこにuserを作成する記述を追加する必要があります。

＊ちなみにCRUDで言うところの「(R)ead」の処理はType Queryにその他「(C)reate、(W)rite、(D)elete」はtype Mutationにという具合に記述します。

以下に新規ユーザー登録の記述を追加してみました。ここでは、name、email、passwordを受け取りデータを登録します。

```graphql/schema.graphql

type Query {
# ・・・
}

type Mutation {
    createUser(
        name: String
            @rules(apply: ["required"])
        email: String
            @rules(apply: ["required",
                "email",
                "unique:users,email"]
            )
        password: String
            @bcrypt
            @rules(apply: ["required"])
    ): User
        @create(model: "App\\User")
}

type User {
# ・・・
}
```

実際に、追加してみます。
<img width="1436" alt="screenshot 2019-07-13 16.00.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/6f613c0a-fd83-0578-90b5-36e9b188f099.png">

# React＋Apollo Clientを用いてフロントエンドに表示

ここではReactとApollo Clientを使って、データを表示したいと思います。

ちなみにこちらの記事を大変参考にさせていただきました。
https://qiita.com/seya/items/e1d8e77352239c4c4897

必要なパッケージのインストール

```
$ npm install apollo-boost react-apollo graphql-tag graphql --save
```

Laravelでログインした後にデフォルトで遷移するページに
ユーザーの名前のリストを表示します。
途中で切れてますが、こんな感じでデータを取得していきます。
<img width="1433" alt="screenshot 2019-07-13 17.37.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/babe3c52-91fa-bbe4-af29-3faac904f31c.png">


``` home.blade.php
<h3>Users</h3>
<div id="users"></div>

<script src="{{ asset('js/app.js') }}" defer></script>
```

```app.js
require('./bootstrap');

require('./components/Users');
```

``` components/Users.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import ApolloClient from 'apollo-boost';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { ApolloProvider } from 'react-apollo';

const client = new ApolloClient({
    uri: 'http://localhost/graphql'
});

// 先ほどplayground上で試したクエリ (emailは抜きました)
const query = gql`
    {
        users (
            count: 10
        ) {
            data {
                id
                name
            }
        }
    }
`;

const Users = () => (
    <Query query={query}>
        {({ loading, data }) => {
            // データ取得中はローディングを表示
            if (loading) return <p>loading...</p>;

            const users = data.users.data;

            return (
                <ul>
                    {users.map(user => (
                        <li key={user.id}>
                            <span>{user.name}</span>
                        </li>
                    ))}
                </ul>
            );
        }}
    </Query>
);

ReactDOM.render(
    <ApolloProvider client={client}>
        <Users />
    </ApolloProvider>,
    document.getElementById('users')
);
```

データ取得中は「loading...」を表示します。
<img width="738" alt="screenshot 2019-07-13 17.35.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/04e8fe61-fc61-dd85-a33e-d1aec4583cc4.png">

取得完了の後、ユーザー名のリストを表示することが出来ました。
<img width="728" alt="screenshot 2019-07-13 17.10.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/341cfad1-0485-8b71-dc27-f0f6450eda0a.png">

とりあえず今回は動くところまでです。
もう少し噛み砕いて色々試してみたいです。