Laravel Api Unifying Response

김윤수·2023년 7월 16일
0

laravel

목록 보기
10/11
post-thumbnail

한 가지 형태로 통일시켜줘야 프론트엔드 개발자가 작업하시기가 편합니다. 원래, http code로 구분했었었는데, 다른 분은 reponse 형태를 통일시켜 달라고 하셔서 작업했습니다.

api response 예

{
    "status": "Success",
    "message": "상품 조회 성공",
    "data": {
        "product": {
            "id": 1,
            "created_at": "2023-03-25 14:33:33",
        }
    }
}

서비스 프로바이더 등록

(당연히 config/app.php에도 등록해줘야함)

<?php
# Providers/ApiResponseServiceProvider.php

declare(strict_types=1);

namespace App\Providers;

use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;
use JustSteveKing\StatusCode\Http;

class ApiResponseServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register(): void
    {

    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot(): void
    {

        Response::macro('success', function (array|string $data, string $message = null, int $code = 200): JsonResponse {
            return Response::json([
                'status'  => 'Success',
                'message' => $message,
                'data'    => $data
            ], $code);
        });

        Response::macro('error', function (string $message, int|Http $code, array|string $data = null): JsonResponse {
            return Response::json([
                'status'  => 'Error',
                'message' => $message,
                'data'    => $data
            ], $code);
        });
    }
}

사용예

public function show(Store $store): JsonResponse
{
    $this->authorize('show', $store);

    return Response::success([
        'store' => new StoreResource($store->load('photos')),
    ], '상점 조회 성공');
}

Error Handler

middleware, validation error까지 모두 통일시킬 것.

<?php

declare(strict_types=1);

namespace App\Exceptions;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->renderable(function (AuthenticationException $e, $request) {
            if ($request->is('api/*')) {
                return Response::error('인증된 사용자가 아닙니다', 401, []);
            }
        });

        $this->renderable(function (AccessDeniedHttpException $e, $request) {
            if ($request->is('api/*')) {
                return Response::error('권한이 없어 요청이 거부되었습니다.', 403, []);
            }
        });

        $this->renderable(function (NotFoundHttpException $e, $request) {
            if ($request->is('api/*')) {
                return Response::error($e->getMessage(), 404, []);
            }
        });

    }

    /**
     * Convert a validation exception into a JSON response.
     *
     * @param ValidationException $e
     * @param Request $request
     * @return JsonResponse
     */
    public function convertValidationExceptionToResponse(ValidationException $e, $request): JsonResponse
    {
        if ($request->expectsJson()) {
            return response()->json([
                "status"  => 'Error',
                "message" => "유효성 검사 실패",
                "data"    => $e->errors()
            ], 422);
        }

        parent::convertValidationExceptionToResponse($e, $request);
    }
}
profile
안녕하세요

0개의 댓글