Как вернуть ошибки AJAX с контроллера Laravel?

Я создаю REST API с Laravel 5.

В Laravel 5 вы можете подклассом App\Http\Requests\Request определить правила проверки, которые должны быть выполнены до того, как будет обработан конкретный маршрут. Например:

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

Если клиент загружает соответствующий маршрут через запрос AJAX, а BookStoreRequest обнаруживает, что запрос не удовлетворяет правилам, он автоматически возвращает ошибку (-ы) как объект JSON. Например:

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

Однако метод Request::rules() может только проверять ввод, и даже если вход действителен, могут возникнуть другие виды ошибок после того, как запрос уже принят и передан контроллеру. Например, скажем, что контроллеру необходимо по какой-то причине записать новую информацию о книге в файл, но файл не может быть открыт:

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

    }

}

Очевидно, я мог бы просто die(), но это супер уродливо. Я бы предпочел вернуть мое сообщение об ошибке в том же формате, что и ошибки проверки. Вот так:

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

Я мог бы создать свой собственный объект JSON и вернуть его, но, конечно же, Laravel поддерживает это.

Какой лучший/самый чистый способ сделать это? Или есть лучший способ вернуть ошибки времени выполнения (в отличие от проверки времени) из LARvel API REST?

Ответ 1

Вы можете установить код состояния в ответе json, как показано ниже:

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

Или просто используя вспомогательную функцию:

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

Ответ 2

Вы можете сделать это разными способами.

Сначала вы можете использовать простой response()->json(), указав код состояния:

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

Или более сложным способом гарантировать, что каждая ошибка является ответом json, вы можете настроить обработчик исключений, чтобы поймать специальное исключение и вернуть json.

Откройте App\Exceptions\Handler и выполните следующие действия:

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

Это приведет к возврату json для любого исключения, созданного в приложении. Теперь мы создаем MyCustomException, например, в приложении/Исключения:

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

Теперь мы можем просто использовать MyCustomException или любое исключение, расширяющее MyCustomException, чтобы вернуть ошибку 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 );

}

Теперь не только исключения, сброшенные через MyCustomException, возвращают ошибку json, но и любое другое исключение, которое вообще генерируется.