Quay lại

Làm thế nào để trả về Exception dưới dạng json trong Laravel Chuyên mục PHP và Laravel    2023-03-14    1.5k Lượt xem    94 Lượt thích    comment-3 Created with Sketch Beta. 0 Bình luận

Làm thế nào để trả về Exception dưới dạng json trong Laravel

Hello anh em lại là mình đây hôm nay mình sẽ hướng dẫn các bạn làm thế nào để trả về exceptions dưới dạng json trong laravel nhé ! Chắc hẳn anh em đã làm nhiều với với restful API rồi đúng không ? khi trên server chúng ta xử và bắn 1 exception về cho phía client, nhưng khi trả về nếu anh em không handle 1 chút thì nó chỉ chả về dưới dạng content-type là html mà thôi như thế thì client khó mà xử lý để thông báo cho user biết được ! Trong cái thằng laravel thì nó có nhiều loại exception khác nhau như : ValidationException, AuthenticationException, NotFoundHttpException, vân vân và mây mây . Mỗi ngoại lệ có thể được xử lý và hiển thị cho người dùng theo cách riêng của nó.

Với cái exception NotFoundHttpException thường được chuyển thành trang 404 nhìn có vẻ Ok, không đến nỗi tệ lắm, đối với AuthenticationException Laravel chỉ chuyển hướng người dùng đến trang đăng nhập với điều này thì có thể hoạt động tốt cho web nhưng với api thì có thể tiêu tốn một lượng thời gian để debugg .

Trong bài viết này, mình sẽ giải thích cách trả về ngoại lệ dưới dạng JSON trong Laravel dưới dạng API và cấu hình nó global trong trình xử lý ngoại lệ. Let's go !!!

Làm thế nào để trả về Exception dưới dạng json trong Laravel

Theo mặc định, Laravel chỉ trả về JSON khi yêu cầu muốn nhận JSON mà thôi , bạn có thể thứ gửi 1 request đến api /api/user endpoint trong postman bạn sẽ nhận được page mặc định , nếu mà các bạn không cấu hình thì với những thông báo của exception trả về nó sẽ dưới dạng html nhìn không được bắt mắt cho lắm

Nếu bạn muốn buộc Laravel trả về phản hồi JSON cho các trường hợp ngoại lệ (exception) và không muốn thay đổi trong code, thì chỉ cần thêm trong Accept header với giá trị application/json. Ví dụ: trong postman:

Để thiết lập vào trong Headers của collection request của bạn , hãy sử dụng tính năng Pre-request scripts thay vì cho vào từng header của mỗi request theo cách thủ công. Để thực hiện việc này, hãy mở menu tùy chọn collection của bạn và nhấp vào Chỉnh sửa:

Sau đó , chọn Pre-request scripts tab và paste đoạn code dưới đây vào nhé

pm.request.headers.add({
    key: "Accept",
    value: "application/json",
});

Postman sẽ tự động add nhưng thông tin header này vào mỗi request trong collection của bạn.

Để server có thể trả về excception json hãy vào trong thư mục app của laravel và sau đó chỉnh sửa Exceptions\Handler class. 

Với class Handler này nó thừa kế từ Illuminate\Foundation\Exceptions\Handler.

Mà trong thằng cha Illuminate\Foundation\Exceptions\Handler này nó có chứa phương thức shouldReturnJson() với nội dung như sau:

protected  function shouldReturnJson($request, Throwable $e)
{
    return $request->expectsJson();
}

Bạn có thể override cái phương thức này trong exception handler và hãy thêm đoạn code dưới đây:

namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
    //....
    protected function shouldReturnJson($request, Throwable $e): bool
    {
        return parent::shouldReturnJson($request, $e) || $request->is("api/*");
    }
}

Trong đoạn code này, mặc định cái behavior được giữ nguyên và ngoài ra, một phản hồi JSON được trả về cho tất cả các yêu cầu chứa chuỗi “api/” trong đường dẫn của chúng. Do đó, Laravel sẽ luôn trả về phản hồi JSON cho các tuyến API.

Các exception mặc định của Laravel là tuyệt vời. Nó đã cung cấp thông báo chi tiết và mã trạng thái response thích hợp. Tuy nhiên, nếu bạn đưa ra một exception tùy chỉnh và tính năng debugg bị tắt, bạn sẽ chỉ nhận được thông báo có nội dung “Lỗi máy chủ” và mã trạng thái 500. Laravel chỉ xuất thông báo cho các lớp mở rộng HttpException.

Điều này được thực hiện vì lý do bảo mật, để ngăn người dùng nhìn thấy thông tin nhạy cảm về ứng dụng của bạn trong môi trường production. Tuy nhiên, bạn có thể muốn trả lại một thông báo response tùy chỉnh của mình.

Ví dụ: Bạn có thể tạo một lớp YourExcepiton và đưa nó vào bất kỳ route nào:

class YourException extends \RuntimeException
{
}
throw new YourException("Your exception message");

Bạn có thể đưa exception của bạn vào bên trong một HttpException chính là bên trong phương thức prepareResponse(). Đây chính là code mặc định trong class cha mà nó đang thừa kế: 

protected function prepareException(Throwable $e)
{
    return match (true) {
        $e instanceof BackedEnumCaseNotFoundException
            => new NotFoundHttpException($e->getMessage(), $e),
        $e instanceof ModelNotFoundException => new NotFoundHttpException(
            $e->getMessage(),
            $e
        ),
        $e instanceof AuthorizationException && $e->hasStatus()
            => new HttpException(
            $e->status(),
            $e->response()?->message() ?:
            Response::$statusTexts[$e->status()] ??
                "Whoops, looks like something went wrong.",
            $e
        ),
        $e instanceof AuthorizationException && !$e->hasStatus()
            => new AccessDeniedHttpException($e->getMessage(), $e),
        $e instanceof TokenMismatchException => new HttpException(
            419,
            $e->getMessage(),
            $e
        ),
        $e instanceof SuspiciousOperationException => new NotFoundHttpException(
            "Bad hostname provided.",
            $e
        ),
        $e instanceof RecordsNotFoundException => new NotFoundHttpException(
            "Not found.",
            $e
        ),
        default => $e,
    };
}

Nó chuyển các exception mặc định của Laravel thành NotFoundHttpException hoặc AccessDeniedHttpException và trả về exception Not found nếu không tìm thấy kết quả phù hợp. Ví dụ: nếu bạn muốn đưa exception của mình vào response “Not found”, bạn có thể sử dụng mã này:

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
    //....
    protected function prepareException(Throwable $e)
    {
        if ($e instanceof YourException) {
            return new NotFoundHttpException($e->getMessage());
        } else {
            return parent::prepareException($e);
        }
    }
}

Ngoài ra, bạn có thể chuyển đổi exception của mình thành basic HttpException bằng trạng thái mã code tùy chỉnh:

namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
    //....
    protected function prepareException(Throwable $e)
    {
        if ($e instanceof YourException) {
            return new HttpException(422, $e->getMessage());
        } else {
            return parent::prepareException($e);
        }
    }
}

KẾT THÚC

Trong bài viết này, tôi đã giải thích cách trả về exception dưới dạng JSON trong Laravel cho các route API và cách tùy chỉnh thông báo exception và mã trạng thái cho các lớp exception của bạn. Hy vọng rằng đã được hữu ích cho bạn! Xin cảm ơn.

 

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday