Laravel 5.7 + GraphQL（ErrorHandling編）

今回はLaravel5.7+GraphQLでエラーハンドリングについての記事です。
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編）](https://qiita.com/ucan-lab/items/c037d4bd07840af32b94)
- Laravel 5.7 + GraphQL（ErrorHandling編）
- [Laravel 5.7 + GraphQL（Test編）](https://qiita.com/ucan-lab/items/1815071cd1cf32d53008)

## 例外を発生させてみる

GraphQLの特徴なのですが、
例外が発生した場合も 200 レスポンスが返り `errors.messages` に例外メッセージが出力されます。

### app/GraphQL/Query/PostQuery.php

```php
    public function resolve($root, $args, $context, ResolveInfo $info) : Post
    {
        throw new \Exception('test error');

        $query = Post::query();

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

        return $query->first();
    }
```

<img width="800" alt="スクリーンショット 2018-10-23 17.04.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/52879/8cb928df-14fa-f517-2167-4cbd2b73bca0.png">

ここまではOKなのですが、
何と発生した例外メッセージがログファイルに出力されません...😭

## GraphQL例外時に実行される関数

### config/graphql.php

```php
    'error_formatter' => [\Folklore\GraphQL\GraphQL::class, 'formatError'],
```

`Folklore\GraphQL\GraphQL` の `formatError` 関数が実行されます。
https://github.com/Folkloreatelier/laravel-graphql/blob/develop/src/Folklore/GraphQL/GraphQL.php#L287-L306

```php
    public static function formatError(Error $e)
    {
        $error = [
            'message' => $e->getMessage()
        ];

        $locations = $e->getLocations();
        if (!empty($locations)) {
            $error['locations'] = array_map(function ($loc) {
                return $loc->toArray();
            }, $locations);
        }

        $previous = $e->getPrevious();
        if ($previous && $previous instanceof ValidationError) {
            $error['validation'] = $previous->getValidatorMessages();
        }

        return $error;
    }
```

ログ出力してないですね💦
`App\Exceptions\Handler` の `report` 関数も通らないので注意です。

## 暫定対応

- https://github.com/ucan-lab/practice-laravel-graphql/commit/d1a8e1dffc48c01c2b73995b5ab9f18d3fdba4d7
- https://github.com/ucan-lab/practice-laravel-graphql/commit/ba52b25ed15174ced07ab1d9785a2487bda33abb

```shell-session
$ php artisan make:exception GraphQLException
```

### src/app/Exceptions/GraphQLException.php

```php
<?php

declare(strict_types = 1);

namespace App\Exceptions;

use Folklore\GraphQL\GraphQL;
use Folklore\GraphQL\Error\ValidationError;
use GraphQL\Error\Error;

class GraphQLException extends GraphQL
{
    public static function formatError(Error $e)
    {
        $error = parent::formatError($e);

        // Logging
        logger()->error($error);
        logger()->error(request()->all());
        logger()->error($e);

        return $error;
    }
}
```

レスポンス、リクエスト、例外情報をログに出力する処理を追加します。
あんまり推奨されるやり方ではない気がしますが、とりあえずログ出力できることを確認しました。
もっと良いやり方があればコメントで教えてください😊

### config/graphql.php

```php
    'error_formatter' => [App\Exceptions\GraphQLException::class, 'formatError'],
```

### storage/logs/laravel.log

```
[2018-10-23 08:03:08] local.ERROR: array (
  'message' => 'test error',
  'locations' => 
  array (
    0 => 
    array (
      'line' => 2,
      'column' => 3,
    ),
  ),
)  
[2018-10-23 08:03:08] local.ERROR: array (
  'query' => '{
  post {
    id
    title
  }
}',
  'variables' => NULL,
  'operationName' => NULL,
)  
[2018-10-23 08:03:08] local.ERROR: Exception: test error in /Users/ucan/study/practice-laravel-graphql/app/GraphQL/Query/PostQuery.php:63
Stack trace:
```

### graphiql

<img width="800" alt="スクリーンショット 2018-10-23 17.04.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/52879/8cb928df-14fa-f517-2167-4cbd2b73bca0.png">

## 参考リンク

- https://github.com/Folkloreatelier/laravel-graphql/issues/209
- https://github.com/Folkloreatelier/laravel-graphql/issues/244