Laravel 5.7 + GraphQL（Pagination編）

今回はLaravel5.7と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編）](https://qiita.com/ucan-lab/items/4eae9e538be9a7a7c5e9)
- [Laravel 5.7 + GraphQL（Dump Server編）](https://qiita.com/ucan-lab/items/ce9abab3fddec0d2d0eb)
- Laravel 5.7 + GraphQL（Pagination編）
- [Laravel 5.7 + GraphQL（ErrorHandling編）](https://qiita.com/ucan-lab/items/fa3bf9b1e7fca1b19d0d)
- [Laravel 5.7 + GraphQL（Test編）](https://qiita.com/ucan-lab/items/1815071cd1cf32d53008)

## Laravel 5.7 ページネーション

```
$users = DB::table('users')->paginate(15);
$users = App\User::paginate(15);
```

Laravelではいくつページネーションする方法がありますが、
一番簡単な方法はQueryBuilderやEloquentBuilderから `paginate` メソッドを使う方法です。

- https://readouble.com/laravel/5.7/ja/pagination.html
- [Illuminate\Database\Query\Builder](https://laravel.com/api/5.7/Illuminate/Database/Query/Builder.html)
- [Illuminate\Database\Eloquent\Builder](https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Builder.html)

## Laravel 5.7 + GraphQL + paginate

GraphQLにて実装します。
前回までのソースコードからの詳細な差分はコミットを参照ください。
https://github.com/ucan-lab/practice-laravel-graphql/commit/cbbe5a812e01bdfde155f12286e24115ec40649e

### app/GraphQL/Query/PostsQuery.php

PostsQueryをページネーションに対応します。

```php
    public function type() : PaginationType
    {
        return GraphQL::pagination(GraphQL::type('PostType'));
    }
```

GraphQLライブラリにPaginationTypeの型が用意されているので設定します。
[Folklore\GraphQL\Support\PaginationType](https://github.com/Folkloreatelier/laravel-graphql/blob/master/src/Folklore/GraphQL/Support/PaginationType.php)

```php
    public function args() : array
    {
        return [
            'id' => [
                'name' => 'id',
                'type' => Type::id(),
            ],
            'ids' => [
                'name' => 'ids',
                'type' => Type::listOf(Type::id()),
            ],
            // take, page のパラメータを追加
            'take' => [
                'type' => Type::int(),
            ],
            'page' => [
                'type' => Type::int(),
            ],
        ];
    }
```

`take` と `page` のパラメータを定義します。
takeは1ページに表示する件数、pageは何ページ目かの指定です。

```php
    public function resolve($root, $args, $context, ResolveInfo $info) : LengthAwarePaginator
    {
        $query = Post::query();

        if (isset($args['id'])) {
            $query->where('id', $args['id']);
        }

        if (isset($args['ids'])) {
            $query->whereIn('id', $args['ids']);
        }

        // ページネーションの処理を追加
        $perPage = $args['take'] ?? 20;
        $page = $args['page'] ?? 1;

        return $query->paginate($perPage, ['*'], 'page', $page);
    }
```

[paginate](https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Builder.html#method_paginate)メソッドに1ページあたりの取得件数とページ番号を渡してあげればokです。
`Illuminate\Pagination\LengthAwarePaginator` を返してあげます。

## 動作確認

```graphql
{
  posts(take: 3, page: 5) {
    items {
      id
      title
    }
    cursor {
      total
      perPage
      currentPage
      hasPages
    }
  }
}
```

items で PostType に定義したフィールドを指定します。
また、 cursor で ページネーションの情報を取得できます。

```json
{
  "data": {
    "posts": {
      "items": [
        {
          "id": "13",
          "title": "Voluptas eos ducimus sit blanditiis qui."
        },
        {
          "id": "14",
          "title": "In quas ex et officia est natus incidunt."
        },
        {
          "id": "15",
          "title": "Harum quaerat consequatur placeat nam est veritatis et."
        }
      ],
      "cursor": {
        "total": 500,
        "perPage": 3,
        "currentPage": 5,
        "hasPages": true
      }
    }
  }
}
```

## 所感

Laravel + GraphQLでページネーションをどうするか？
と情報を探していたところ、PaginationTypeを追加するIssueがmasterにマージされていたことを発見しました。
https://github.com/Folkloreatelier/laravel-graphql/pull/242

思ったよりシンプルに書けて凄かったです😊
ページネーションのテストコードがとても参考になりましたので参考にしたコード一覧も載せておきます！

### 参考コード

- https://github.com/Folkloreatelier/laravel-graphql/blob/master/src/Folklore/GraphQL/Support/PaginationType.php
- https://github.com/Folkloreatelier/laravel-graphql/blob/master/src/Folklore/GraphQL/Support/PaginationCursorType.php
- https://github.com/Folkloreatelier/laravel-graphql/blob/develop/tests/Objects/ExamplesPaginationQuery.php