web-dev-qa-db-fra.com

Comment renvoyer les erreurs AJAX à partir d'un contrôleur Laravel?

Je construis une API REST avec Laravel 5.

Dans Laravel 5, vous pouvez sous-classer App\Http\Requests\Request Pour définir les règles de validation qui doivent être satisfaites avant qu'un itinéraire particulier soit traité. Par exemple:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class BookStoreRequest extends Request {

    public function authorize() {
        return true;
    }

    public function rules() {
        return [
            'title' => 'required',
            'author_id' => 'required'
        ];
    }
}

Si un client charge la route correspondante via une requête AJAX et BookStoreRequest constate que la requête ne satisfait pas aux règles, il renverra automatiquement les erreurs sous la forme d'un Objet JSON. Par exemple:

{
  "title": [
    "The title field is required."
  ]
}

Cependant, la méthode Request::rules() ne peut valider que l'entrée et même si l'entrée est valide, d'autres types d'erreurs peuvent survenir après que la demande a déjà été acceptée et transmise au contrôleur. Par exemple, disons que le contrôleur doit écrire les informations du nouveau livre dans un fichier pour une raison quelconque - mais le fichier ne peut pas être ouvert:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use App\Http\Requests\BookCreateRequest;

class BookController extends Controller {

    public function store( BookStoreRequest $request ) {

        $file = fopen( '/path/to/some/file.txt', 'a' );

        // test to make sure we got a good file handle
        if ( false === $file ) {
            // HOW CAN I RETURN AN ERROR FROM HERE?
        }

        fwrite( $file, 'book info goes here' );
        fclose( $file );

        // inform the browser of success
        return response()->json( true );

    }

}

Évidemment, je pourrais simplement die(), mais c'est super moche. Je préfère renvoyer mon message d'erreur dans le même format que les erreurs de validation. Comme ça:

{
  "myErrorKey": [
    "A filesystem error occurred on the server. Please contact your administrator."
  ]
}

Je pourrais construire mon propre objet JSON et le retourner — mais sûrement Laravel le supporte nativement.

Quelle est la meilleure façon/la plus propre de procéder? Ou existe-t-il un meilleur moyen de renvoyer des erreurs d'exécution (par opposition à des erreurs de validation) à partir d'une API Laravel REST?

14
greenie2600

Vous pouvez définir le code d'état dans votre réponse json comme ci-dessous:

return Response::json(['error' => 'Error msg'], 404); // Status code here

Ou tout simplement en utilisant la fonction d'assistance:

return response()->json(['error' => 'Error msg'], 404); // Status code here
20
Jilson Thomas

Vous pouvez le faire de plusieurs façons.

Tout d'abord, vous pouvez utiliser la simple response()->json() en fournissant un code d'état:

return response()->json( /** response **/, 401 );

Ou, d'une manière plus complexe pour vous assurer que chaque erreur est une réponse json, vous pouvez configurer un gestionnaire d'exceptions pour intercepter une exception spéciale et renvoyer json.

Ouvert App\Exceptions\Handler et procédez comme suit:

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        NotFoundHttpException::class,
        // Don't report MyCustomException, it's only for returning son errors.
        MyCustomException::class
    ];

    public function render($request, Exception $e)
    {
        // This is a generic response. You can the check the logs for the exceptions
        $code = 500;
        $data = [
            "error" => "We couldn't hadle this request. Please contact support."
        ];

        if($e instanceof MyCustomException) {
            $code = $e->getStatusCode();
            $data = $e->getData();
        }

        return response()->json($data, $code);
    }
}

Cela retournera un json pour toute exception levée dans l'application. Maintenant, nous créons MyCustomException, par exemple dans app/Exceptions:

class MyCustomException extends Exception {

    protected $data;
    protected $code;

    public static function error($data, $code = 500)
    {
        $e = new self;
        $e->setData($data);
        $e->setStatusCode($code);

        throw $e;
    }

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

    public function setData($data)
    {
        $this->data = $data;
    }


    public function getStatusCode()
    {
        return $this->code;
    }

    public function getData()
    {
        return $this->data;
    }
}

Nous pouvons maintenant simplement utiliser MyCustomException ou toute exception étendant MyCustomException pour renvoyer une erreur json.

public function store( BookStoreRequest $request ) {

    $file = fopen( '/path/to/some/file.txt', 'a' );

    // test to make sure we got a good file handle
    if ( false === $file ) {
        MyCustomException::error(['error' => 'could not open the file, check permissions.'], 403);

    }

    fwrite( $file, 'book info goes here' );
    fclose( $file );

    // inform the browser of success
    return response()->json( true );

}

Désormais, non seulement les exceptions levées via MyCustomException renverront une erreur json, mais toute autre exception levée en général.

6
Blue Genie