라라벨 Swagger(Open API) 적용 가이드

|

스웨거란?

스웨거(Swagger) 는 백엔드 개발자가 API 와 연동하기 쉽도록 고안된 문서 제작 도구입니다.
프론트 엔드 개발자에게 정보를 전달할 수 있게 되는 매개체인 것이죠. 표면적으로는 그렇습니다.

그러나 심층적으로 다가가보면, 백엔드 개발을 할 때 원하는 기능을 정확하게 설계 및 구축을 지원하게 됩니다.
단순히 스웨거를 만들기 위해 반드시 해야 하는 주석 처리만 잘 하더라도 GET인지, String으로 받아야 하는지, 리턴은 어떻게 해야하는 지 등의 표본이 존재하기에 개발 협업에 많은 소통시간을 줄일 수 있게 됩니다.

API 문서 자동 생성

Swagger 어노테이션은 라라벨 코드에서 고려해야 할 모범 사례이며 API 엔드포인트, 요청, 매개변수, 응답 구조, 인증 방법 등을 설명하는데 사용됩니다. 이는 사용자 친화적인 형식으로 제공되기 때문에 개발자와 비개발자 모두 API 를 쉽게 이해할 수 있습니다.

일관성

Swagger 는 구버전, 신버전, 개발 언어가 다르거나 프레임워크가 다름에도 디자인과 접근방식이 일관적이라는 특징을 가지고 있습니다. 이는 소통에 생기는 문제를 최소화 하며 학습의 낭비가 적어지는 장점을 가지고 있습니다.

유지 보수의 용이성

darkaonline/l5-swagger 도구를 활용하면 라라벨과의 연동성을 고려하여 개발되었기 때문에 스웨거를 자동화하기 용이합니다.

Swagger 설치하기

composer require darkaonline/l5-swagger

삭제는 composer remove 명령어를 통해 할 수 있습니다.

php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

위의 명령어를 실행하면 /config/l5-swagger.php 파일과 /resources/view/vendor 아래에 l5-swagger 관련 뷰 파일이 생성됩니다.

Swagger 페이지 들어가기

Swagger 적용화면

http://localhost/api/documentation/ 으로 접근해보시면 Swagger 를 만나보실 수 있습니다.

적용방법

컨트롤러에 추가하기

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

/**
 * @OA\Info(
 *     title="Laravel Home Traning API",
 *     version="1.0"
 * )
 */
class Controller extends BaseController
{
    use AuthorizesRequests, ValidatesRequests;
}

먼저 어노테이션을 추가해야합니다. app/Http/Controllers/Controller.php 에 존재하는 BaseController 바로 위에 @OA\Info.... 주석을 추가하면 됩니다.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\PersonalTrainer;

class WeightLossConsultingController extends Controller
{
    /**
     * @OA\Schema(
     *     schema="Recommendation",
     *     type="object",
     *     @OA\Property(
     *         property="solutionType",
     *         type="string",
     *         description="추천 유형 (DIET 또는 FITNESS)"
     *     ),
     *     @OA\Property(
     *         property="recommendationName",
     *         type="string",
     *         description="추천 프로그램 이름"
     *     )
     * )
     *
     * @OA\Get(
     *     path="/api/v1/how-to-lose-weight",
     *     operationId="getHowToLoseWeight",
     *     tags={"체중 조절 컨설팅"},
     *     summary="체중 조절 컨설팅 안내",
     *     description="사용자의 [생활 스타일 태그 / 선호하는 해결책 유형] 기반으로 체중 감량에 대한 개인화된 조언 제공",
     *     @OA\Parameter(
     *         name="solutionType",
     *         in="query",
     *         required=false,
     *         description="해결책 유형 (DIET / FITNESS / 공백값), 비워둘 경우 모든 유형의 추천을 제공",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Parameter(
     *         name="lifeStyleTags",
     *         in="query",
     *         required=true,
     *         description="사용자의 생활 스타일을 나타내는 태그, 쉼표로 구분",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="성공적으로 추천 정보를 반환",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(
     *                 property="recommendations",
     *                 type="array",
     *                 @OA\Items(ref="#/components/schemas/Recommendation")
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response="400",
     *         description="잘못된 요청",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(
     *                 property="error",
     *                 type="string",
     *                 description="에러 메시지"
     *             )
     *         )
     *     )
     * )
     */

    public function howToLoseWeight(Request $request): \Illuminate\Http\JsonResponse
    {
        $solutionType = $request->input('solutionType');
        $lifeStyleTags = $request->input('lifeStyleTags');

        // solutionType 지정한 태그값 or 공백만 허용
        if (!($solutionType === 'DIET' || $solutionType === 'FITNESS' || empty($solutionType))) {
            return response()->json([
                'error' => '유효하지 않은 solutionType 값입니다.'
            ], 400);
        }

        // lifeStyleTags 값이 존재하지 않을 경우 400 에러 메시지 반환
        if (empty($lifeStyleTags)) {
            return response()->json([
                'error' => 'lifeStyleTags 값이 최소 1개 이상 있어야 합니다.'
            ], 400);
        }

        /* Tag 쪼개기 (조건 , ) */
        $lifeStyleTagsArray = explode(',', $lifeStyleTags);

        /* Service 추가 */
        $personalTrainer = new PersonalTrainer();
        $recommendations = $personalTrainer->getRecommendation($solutionType, $lifeStyleTagsArray);

        /* array_values 로 2차 에러 발생 방지 */
        return response()->json(['recommendations' => array_values($recommendations)]);

    }
}

그 다음은 직접 만든 컨트롤러 클래스 안에 어노테이션을 적용하면 됩니다.

api-docs.json 명세서 생성하기

php artisan l5-swagger:generate

위의 명령어를 입력하여 api-docs.json 파일을 생성합니다.
생성되는 경로는 /storage/api-docs/api-docs.json 입니다. 이 파일은 바로 API 명세서입니다.

Swagger 에 명세서 파일 생성된 모습

들어와 보게 되면 위와 같이 표시되게 됩니다.

Open API 와 RESTful API

RESTful API 를 구축하고 문서화 할 때 라라벨은 우아하고 효율적인 기능으로 인해 좋은 선택이 될 수 있습니다.
그러나 서비스의 크기가 커져 API 가 점점 더 복잡해진다면 명확하고 최신 문서를 유지하는 것이 어려워 질 수 있습니다.

여기서 사용되는 Swagger 는 오픈 소스 도구로, 이미 자바 스프링이나 Nest JS 에서 사용되는 모습을 보았고 마찬가지로 라라벨에도 적용할 수 있다는 장점을 가지고 있습니다.

트러블슈팅

  • Required @OA\PathItem() not found

만약 이런 에러가 발생했다면 현재 문서를 만들려고 보니 어노테이션(주석) 이 하나도 없더라
만들어달라 라고 이해하시면 됩니다.

참조

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다