web-dev-qa-db-fra.com

Laravel API, comment gérer correctement les erreurs

Quelqu'un sait quel est le meilleur moyen de gérer les erreurs dans Laravel, y a-t-il des règles ou quelque chose à suivre?

Actuellement, je fais ceci: 

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.");
  }
}

Et les paramètres setStatusCode et responseWithError proviennent du père de mon contrôleur:

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

    return $this;
}

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

}

Mais est-ce un bon moyen de gérer les erreurs d'API? Je vois un moyen différent de gérer les erreurs sur le Web. Quel est le meilleur?

Merci.

4
Jessy

Essayez ceci, je l'ai utilisé dans mon projet (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;
}

Maintenant, gérer l'exception 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);
}

Après cette réponse de gestionnaire Api personnalisée 

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);
}

Toujours ajouter Accept: application/json dans votre demande api ou json.

6
rkj

Laravel est déjà capable de gérer les réponses JSON par défaut.

Sans que vous personnalisiez la méthode de rendu dans app\Handler.php, vous pouvez simplement lancer une exception Symfony\Component\HttpKernel\Exception\HttpException, le gestionnaire par défaut reconnaîtra si l'en-tête de demande contient Accept: application/json et imprimera un json message d'erreur en conséquence.

Si le mode débogage est activé, la sortie de pile sera également générée au format json.

Voici un exemple rapide:

<?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;
    }
}

Voici la réponse de laravel avec debug off

{
    "message": "My custom error"
}

Et voici la réponse avec debug sur

{
    "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": "->"
        },

        ...
    ]
}

En utilisant HttpException, l'appel renvoie le code d'état http de votre choix (dans ce cas, l'erreur de serveur interne 500)

1
Andrea Mauro

À mon avis, je vais garder les choses simples.

Renvoyer une réponse avec le code d'erreur HTTP et un message personnalisé.

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

Ou si vous voulez lancer une erreur surprise, vous pouvez faire:

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

Vous pouvez même l'utiliser pour envoyer des réponses réussies:

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

Ainsi, quel que soit le service consommant votre API, il peut s’attendre à recevoir les mêmes réponses pour les mêmes demandes.

Vous pouvez également voir à quel point vous pouvez le rendre flexible en transmettant le code d'état HTTP.

0
user3574492