1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaravelでAPIのエラーレスポンスを共通化する

Last updated at Posted at 2023-04-28

はじめに

Laravel で API を開発していると、フロントの都合の良いようにエラーのレスポンスを共通化しなければなりません。
色々な方法があるかと思いますが、今回はその一つをご紹介します。

どうするか

  1. エラーのキャッチ
  2. API へのアクセスかを判定
  3. 例外ごとに整形
  4. json で返却

実装

以下のように実装しました。順に解説します。

Handler.php
public function register(): void
{
    // 1. エラーのキャッチ
    $this->renderable(function (Throwable $e, $request) {
        // 2. APIへのアクセスかを判定
        if ($this->shouldReturnJson($request, $e)) {
            $response = [];
            // 3. 例外ごとに整形
            switch (true) {
                case $e instanceof AuthenticationException:
                    $statusCode = 401;
                    $response['message'] = '認証エラーが発生しました。';
                    break;
                case $e instanceof ValidationException:
                    $statusCode = $e->status;
                    $response['message'] = 'リクエストが不正です。';
                    $errors = [];
                    foreach ($e->validator->errors()->getMessages() as $key => $value) {
                        $errors[] = [
                            'property' => $key,
                            'message' => $value[0]
                        ];
                    }
                    $response['errors'] = $errors;
                    break;
                default:
                    if (method_exists($e, 'getStatusCode')) {
                        $statusCode = $e->getStatusCode();
                    } else {
                        $statusCode = 500;
                    }
                    $response['message'] = 'サーバーエラーが発生しました。';

            }
            if (config('app.debug')) {
                $response['trace'] = $e->getTrace();
                $response['code'] = $e->getCode();
            }
            // 4. jsonで返却
            return response()->json($response, $statusCode);
        }
        return null;
    });
}

1. エラーのキャッチ

Handler.php
// 1. エラーのキャッチ
$this->renderable(function (Throwable $e, $request)

Laravel ではアプリケーションが投げるすべての例外を Handler.php で取得できます。
ここでは renderable を使用してエラー発生時の分岐や動作を登録します。

2. API へのアクセスかを判定

Handler.php
// 2. APIへのアクセスかを判定
if ($this->shouldReturnJson($request, $e))

shouldReturnJson でリクエストヘッダーにAccept: application/jsonがある場合 API へのアクセスとみなします。
公式サイトのサンプルでは$request->is('api/*')で判定しているのでそちらでも良いと思います。

3. 例外ごとに整形

Handler.php
case $e instanceof ValidationException:
    $statusCode = $e->status;
    $response['message'] = 'リクエストが不正です。';
    $errors = [];
    foreach ($e->validator->errors()->getMessages() as $key => $value) {
        $errors[] = [
            'property' => $key,
            'message' => $value[0]
        ];
    }
    $response['errors'] = $errors;
    break;

発生した例外ごとにステータスコードと任意のエラーメッセージを設定しています。
例ではバリデーションエラーが発生した際の個別メッセージにも対応しています。

今回は以下のように開発環境に限りどこで例外が発生したかを追えるようにもしました。

Handler.php
if (config('app.debug')) {
    $response['trace'] = $e->getTrace();
    $response['code'] = $e->getCode();
}

4. json で返却

Handler.php
return response()->json($response, $statusCode);

ステータスコードとエラーメッセージを json で返却します。

結果

エラーはこのように返却されます。

{
    "message": "リクエストが不正です。",
    "errors": [
        {
            "property": "test",
            "message": "testは必ず指定してください。"
        }
    ]
}

さいごに

そこまで複雑にならずエラーレスポンスの共通化ができました。
今回は一部のみ例で示しましたが実際は case がもっと増えると思います。
誰かのお役に立てれば幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?