web-dev-qa-db-ja.com

Laravel API、エラーを適切に処理する方法

Laravelでエラーを処理する最良の方法は何か知っていますか、従うべきルールや何かがありますか?

現在、私はこれをやっています:

public function store(Request $request)
{
  $plate = Plate::create($request->all());

  if ($plate) {
    return $this->response($this->plateTransformer->transform($plate));
  } else {
    // Error handling ?
    // Error 400 bad request
    $this->setStatusCode(400);
    return $this->responseWithError("Store failed.");
  }
}

そして、setStatusCodeとresponseWithErrorは私のコントローラーの父から来ています:

public function setStatusCode($statusCode)
{
    $this->statusCode = $statusCode;

    return $this;
}

public function responseWithError ($message )
{
    return $this->response([
        'error' => [
            'message' => $message,
            'status_code' => $this->getStatusCode()
        ]
    ]);

}

しかし、これはAPIエラーを処理するための良い方法ですか?

ありがとう。

10
Jessy

これを試して、プロジェクトで使用しました(app/Exceptions/Handler.php)

public function render($request, Exception $exception)
{
    if ($request->wantsJson()) {   //add Accept: application/json in request
        return $this->handleApiException($request, $exception);
    } else {
        $retval = parent::render($request, $exception);
    }

    return $retval;
}

API例外を処理するようになりました

private function handleApiException($request, Exception $exception)
{
    $exception = $this->prepareException($exception);

    if ($exception instanceof \Illuminate\Http\Exception\HttpResponseException) {
        $exception = $exception->getResponse();
    }

    if ($exception instanceof \Illuminate\Auth\AuthenticationException) {
        $exception = $this->unauthenticated($request, $exception);
    }

    if ($exception instanceof \Illuminate\Validation\ValidationException) {
        $exception = $this->convertValidationExceptionToResponse($exception, $request);
    }

    return $this->customApiResponse($exception);
}

カスタムApiハンドラーの応答後

private function customApiResponse($exception)
{
    if (method_exists($exception, 'getStatusCode')) {
        $statusCode = $exception->getStatusCode();
    } else {
        $statusCode = 500;
    }

    $response = [];

    switch ($statusCode) {
        case 401:
            $response['message'] = 'Unauthorized';
            break;
        case 403:
            $response['message'] = 'Forbidden';
            break;
        case 404:
            $response['message'] = 'Not Found';
            break;
        case 405:
            $response['message'] = 'Method Not Allowed';
            break;
        case 422:
            $response['message'] = $exception->original['message'];
            $response['errors'] = $exception->original['errors'];
            break;
        default:
            $response['message'] = ($statusCode == 500) ? 'Whoops, looks like something went wrong' : $exception->getMessage();
            break;
    }

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

    $response['status'] = $statusCode;

    return response()->json($response, $statusCode);
}

常にAccept: application/json apiまたはjsonリクエストで。

18
rkj

Laravelはすでにデフォルトでjson応答を管理できます。

App\Handler.phpのrenderメソッドをカスタマイズせずにSymfony\Component\HttpKernel\Exception\HttpExceptionをスローするだけで、デフォルトハンドラーはリクエストヘッダーにAccept:application/jsonが含まれているかどうかを認識します。それに応じてJSONエラーメッセージを出力します。

デバッグモードが有効になっている場合、json形式でスタックトレースも出力されます。

以下に簡単な例を示します。

<?php

...

use Symfony\Component\HttpKernel\Exception\HttpException;

class ApiController
{
    public function myAction(Request $request)
    {
        try {
            // My code...
        } catch (\Exception $e) {
            throw new HttpException(500, $e->getMessage());
        }

        return $myObject;
    }
}

laravelデバッグをオフにした応答

{
    "message": "My custom error"
}

そして、これはデバッグをオンにした応答です

{
    "message": "My custom error",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",
    "file": "D:\\www\\myproject\\app\\Http\\Controllers\\ApiController.php",
    "line": 24,
    "trace": [
        {
            "file": "D:\\www\\myproject\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php",
            "line": 48,
            "function": "myAction",
            "class": "App\\Http\\Controllers\\ApiController",
            "type": "->"
        },
        {
            "file": "D:\\www\\myproject\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php",
            "line": 212,
            "function": "dispatch",
            "class": "Illuminate\\Routing\\ControllerDispatcher",
            "type": "->"
        },

        ...
    ]
}

HttpExceptionを使用すると、呼び出しは選択したhttpステータスコードを返します(この場合、内部サーバーエラー500)

3
Andrea Mauro

私の意見では、シンプルに保ちます。

HTTPエラーコードとカスタムメッセージを含む応答を返します。

return response()->json(['error' => 'You need to add a card first'], 500);

または、キャッチされたエラーをスローする場合は、次のようにすることができます:

   try {
     // some code
    } catch (Exception $e) {
        return response()->json(['error' => $e->getMessage()], 500);
    }

成功した応答を送信するためにこれを使用することもできます:

return response()->json(['activeSubscription' => $this->getActiveSubscription()], 200);

この方法により、どのサービスがAPIを消費しても、同じリクエストに対して同じ応答を受け取ることが期待できます。

また、HTTPステータスコードを渡すことで、柔軟性を高めることができます。

1
user3574492