Как заставить Laravel вернуть пользовательскую ошибку для API REST JSON

Я разрабатываю какой-то RESTful API. Когда возникает какая-то ошибка, Я бросаю App::abort($code, $message) ошибка.

проблема в том, что я хочу, чтобы он бросил массив JSON с ключами "код" и "сообщение", Каждый из которых содержит вышеупомянутые данные.

Array
(
    [code] => 401
    [message] => "Invalid User"
)

кто-нибудь знает, возможно ли это, и если да, то как я это делаю?

6 ответов


перейти к вашей app/start/global.php.

это преобразует все ошибки для 401 и 404 к пользовательской ошибке json вместо Whoops stacktrace. Добавьте это:

App::error(function(Exception $exception, $code)
{
    Log::error($exception);

    $message = $exception->getMessage();

    // switch statements provided in case you need to add
    // additional logic for specific error code.
    switch ($code) {
        case 401:
            return Response::json(array(
                    'code'      =>  401,
                    'message'   =>  $message
                ), 401);
        case 404:
            $message            = (!$message ? $message = 'the requested resource was not found' : $message);
            return Response::json(array(
                    'code'      =>  404,
                    'message'   =>  $message
                ), 404);        
    }

});

это один из многих вариантов для обработки этой ошибки.


создание API лучше всего создать свой собственный помощник, как Responser::error(400, 'damn') что расширяет Response класса.

что-то вроде:

public static function error($code = 400, $message = null)
{
    // check if $message is object and transforms it into an array
    if (is_object($message)) { $message = $message->toArray(); }

    switch ($code) {
        default:
            $code_message = 'error_occured';
            break;
    }

    $data = array(
            'code'      => $code,
            'message'   => $code_message,
            'data'      => $message
        );

    // return an error
    return Response::json($data, $code);
}

вы можете передать массив возвращаемому ответу JSON:

$returnData = array(
    'status' => 'error',
    'message' => 'An error occurred!'
);
return Response::json($returnData, 500);

вот что я использую (Laravel 5.2):

по: https://laravel.com/docs/5.2/errors , можно задать пользовательскую функцию render для ошибок app\Exceptions\Handler.php. Все, что я сделал, это изменил свою функцию рендеринга на это:

    /**
     * Render an exception into an HTTP response.
     * Updated to return json for a request that wantsJson 
     * i.e: specifies 
     *      Accept: application/json
     * in its header
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        if ($request->ajax() || $request->wantsJson()) {
            return response()->json(
                          $this->getJsonMessage($e), 
                          $this->getExceptionHTTPStatusCode($e)
                        );
        }
        return parent::render($request, $e);
    }

    protected function getJsonMessage($e){
        // You may add in the code, but it's duplication
        return [
                  'status' => 'false',
                  'message' => $e->getMessage()
               ];
    }

    protected function getExceptionHTTPStatusCode($e){
        // Not all Exceptions have a http status code
        // We will give Error 500 if none found
        return method_exists($e, 'getStatusCode') ? 
                         $e->getStatusCode() : 500;
    }

после этого, все, что вам нужно сделать, это убедиться, что все ваши запросы API указать Accept: application/json заголовок. Надеюсь, это поможет:)


согласно ответу Ибрагима, не каждый запрос ajax хочет JSON, отвечая на "код состояния"и "статус" не нужен, так как они оба означают одно и то же. Более того, нет необходимости упоминать в ответе "статус" вообще, так как код ответа "говорит" это. Что-то вроде этого должно работать идеально:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if ($request->wantsJson())
        return response()->json(
            ['message' => $e->getMessage()],
            method_exists($e, 'getStatusCode') ? $e->getStatusCode() : 500);

    return parent::render($request, $e);
}

вот что я использовал в 5.6, чтобы вернуть тот же тип ответа, что и встроенный validate способ:

response()->json(['errors' => ['email' => ['The email is invalid.']]], 422);


В Laravel5.6, я обычно указываю пользовательскую функцию рендеринга для ошибок в app\Exceptions\Handler.php. Все, что я сделал, это изменил свою функцию рендеринга на это:

/**
 * Render an exception into an HTTP response.
 *
 * @param \Illuminate\Http\Request $request
 * @param \Exception               $e
 *
 * @return Response
 */
public function render($request, Exception $e)
{
    if ($request->wantsJson() && !($e instanceof ValidationException)) {
        $response = [
            'message' => (string)$e->getMessage(),
            'status_code' => 400,
        ];

        if ($e instanceof HttpException) {
            $response['message'] = Response::$statusTexts[$e->getStatusCode()];
            $response['status_code'] = $e->getStatusCode();
        } else if ($e instanceof ModelNotFoundException) {
            $response['message'] = Response::$statusTexts[Response::HTTP_NOT_FOUND];
            $response['status_code'] = Response::HTTP_NOT_FOUND;
        }

        if ($this->isDebugMode()) {
            $response['debug'] = [
                'exception' => get_class($e),
                'trace' => $e->getTrace()
            ];
        }

        return response()->json([
            'status'      => 'failed',
            'status_code' => $response['status_code'],
            'massage'     => $response['message'],
        ], $response['status_code']);
    }

    return parent::render($request, $e);
}