Laravel 5.7 + GraphQL（Relation編）

[LaravelとGraphQLでAPI開発](https://qiita.com/ucan-lab/items/b1796b083ac5c0bcb019)こちらの記事の続きです。

今回はGraphQLでリレーションのデータを取得する方法をご紹介します。

## シリーズ記事

- [LaravelとGraphQLでAPI開発](https://qiita.com/ucan-lab/items/b1796b083ac5c0bcb019)
- [Laravel 5.7 + GraphQL（Install編）](https://qiita.com/ucan-lab/items/32969d6a9b5aa99b475e)
- [Laravel 5.7 + GraphQL（ScalarType編）](https://qiita.com/ucan-lab/items/32ee8dd18974d6146456)
- Laravel 5.7 + GraphQL（Relation編）
- [Laravel 5.7 + GraphQL（Dump Server編）](https://qiita.com/ucan-lab/items/ce9abab3fddec0d2d0eb)
- [Laravel 5.7 + GraphQL（Pagination編）](https://qiita.com/ucan-lab/items/c037d4bd07840af32b94)
- [Laravel 5.7 + GraphQL（ErrorHandling編）](https://qiita.com/ucan-lab/items/fa3bf9b1e7fca1b19d0d)
- [Laravel 5.7 + GraphQL（Test編）](https://qiita.com/ucan-lab/items/1815071cd1cf32d53008)

## 記事のモデル、マイグレーション、ファクトリを作る

https://github.com/ucan-lab/practice-laravel-graphql/commit/1c17b14bd679833ccc889cd58504f49cbd2df9f0

```shell-session
$ php artisan make:model -mf Post
```

GraphQLを使うのでコントローラは作りません。
ユーザーのモデルとシーダーに記事リレーションを修正します。

```shell-session
$ php artisan migrate:fresh --seed
```

マイグレーション＆シーディングを実行する。
これは本題ではないのでコミットを参照ください。

## １対多のリレーションデータを取得の例

https://github.com/ucan-lab/practice-laravel-graphql/commit/64d8c2fa7b8f6bfe96fd46b7d14848c06ee0a00b

### PostTypeのGraphQL独自型の定義

```shell-session
$ php artisan make:graphql:type PostType
```

### config/graphql.php

```php
    'types' => [
        App\GraphQL\Type\UserType::class,
        App\GraphQL\Type\PostType::class,
        // custom scalar type
        App\GraphQL\Scalars\DateTimeType::class,
    ],
```

PostType を登録します。

### app/GraphQL/Type/PostType.php

```php
<?php

declare(strict_types = 1);

namespace App\GraphQL\Type;

use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as BaseType;
use GraphQL;

class PostType extends BaseType
{
    protected $attributes = [
        'name' => 'PostType',
        'description' => 'post type'
    ];

    public function fields() : array
    {
        return [
            'id' => [
                'type' => Type::id(),
                'description' => 'The id of the user'
            ],
            'title' => [
                'type' => Type::string(),
                'description' => 'The title of post',
            ],
            'content' => [
                'type' => Type::string(),
                'description' => 'The content of post',
            ],
        ];
    }
}
```

`PostType` GraphQL独自型のfieldsを定義します。

### app/GraphQL/Type/UserType.php

```php
    public function fields() : array
    {
        return [
            'posts' => [
                'type' => Type::listOf(GraphQL::type('PostType')),
                'description' => 'The posts of user',
            ],
        ];
    }
```

### １対多 動作確認

```graphql
{
  user(id: 1) {
    id
    name
    posts {
      title
      content
    }
  }
}
```

`posts { ... }` と書いてあげるだけでリレーションデータを引っ張ってきてくれます！

```json
{
  "data": {
    "user": {
      "id": "1",
      "name": "Prof. Mozell Beer",
      "posts": [
        {
          "title": "Nihil in autem autem molestiae.",
          "content": "Quod dolores sunt aspernatur voluptatem officia aut voluptatum. In dolores non dolore ut nesciunt voluptatem laboriosam. Pariatur aut et tenetur dolor doloribus."
        },
        {
          "title": "Dolores tenetur deserunt velit qui et in minus velit.",
          "content": "Quaerat sint excepturi dicta ut maiores. Est corporis expedita aut rerum sapiente. Explicabo hic dolorem nulla animi delectus voluptatem."
        },
        {
          "title": "Quia nostrum sapiente accusamus qui saepe.",
          "content": "Debitis praesentium autem est doloribus eius saepe. Iste dolorum consectetur incidunt ea aliquid et voluptas aut. Dignissimos sed autem eius adipisci. Eligendi eius pariatur aut earum."
        },
        {
          "title": "Quaerat corrupti inventore consectetur ipsam blanditiis.",
          "content": "Ad facere non officia commodi earum. Officiis deleniti itaque occaecati qui natus et. Fuga molestias alias atque adipisci. Itaque id praesentium ea."
        },
        {
          "title": "Nihil a illum magnam.",
          "content": "A quis deleniti quia quasi odio. Quas qui odit placeat sit tempora nulla voluptas. Consequatur nemo sit consequatur enim ratione."
        },
        {
          "title": "Aut tempore aut et enim.",
          "content": "Provident qui velit magni et. Molestiae qui dignissimos assumenda voluptas excepturi magnam ut. Nesciunt odit atque repudiandae ex delectus quia numquam."
        },
        {
          "title": "Beatae ipsa dignissimos eveniet officia eveniet explicabo.",
          "content": "Soluta expedita aut sit tempore. Et perferendis nemo culpa sit velit voluptatum. Quis natus iusto aut consectetur ex. Error voluptates ut quam. Ut molestias incidunt nihil rerum et itaque blanditiis."
        },
        {
          "title": "Quo non labore vel neque.",
          "content": "Officiis recusandae sunt ullam sit eos. Aspernatur architecto repellendus aut aliquid natus. Iusto praesentium perspiciatis veritatis sit ratione sequi."
        },
        {
          "title": "Dignissimos quia est fugit omnis sit dolores alias.",
          "content": "Non maiores nesciunt adipisci. Est aut distinctio soluta ducimus sed. Harum labore ut voluptas ea qui."
        },
        {
          "title": "Minus asperiores dolorem provident quo.",
          "content": "Voluptas ut odio qui eum totam sed neque. Necessitatibus excepturi eius quas iure. Quia enim voluptatem est molestiae non. Tenetur similique ullam qui iure enim voluptates voluptatem."
        }
      ]
    }
  }
}
```

こんな感じでリレーションデータを取得できます。
これの凄いところは、定義を追加しただけでライブラリ側で判断してユーザーが投稿した記事の情報を取得できているところです。

## １対多 (Inverse)のリレーションデータを取得の例

### 記事のQueryを作る

```shell-session
$ php artisan make:graphql:query PostQuery
$ php artisan make:graphql:query PostsQuery
```

### app/GraphQL/Type/PostType.php

```php
    public function fields() : array
    {
        return [
            'user' => [
                'type' => GraphQL::type('UserType'),
                'description' => 'The user of post',
            ],
        ];
    }
```

１対多 (Inverse)の設定はこれだけです。

### １対多 (Inverse) 動作確認

```graphql
{
  post(id: 123) {
    id
    title
    user {
      id
      name
    }
  }
}
```

`user { ... }` と書いてあげるだけでリレーションデータを引っ張ってきてくれます！

```json
{
  "data": {
    "post": {
      "title": "Quae itaque maxime sit eius ducimus qui quas.",
      "user": {
        "id": "13",
        "name": "Melany Johnson"
      }
    }
  }
}
```

とても簡潔に記述できます。

## リレーションデータ取得処理のカスタマイズ

### app/GraphQL/Type/PostType.php

```php
    /**
     * ユーザー
     *
     * @param Post $root
     * @param array $args
     * @return User
     */
    protected function resolveUserField(Post $root, array $args) : User
    {
        logger('test');
        return $root->user;
    }
```

`resolveフィールド名Field` resolver関数を用意すればリレーションデータを取得する前に処理を差し込むことができます。
とても柔軟に対応できるので素敵だなぁと思いました。