티스토리 뷰
Laravel Swagger 쉽게 적용하기 (feat. vyuldashev/laravel-openapi 패키지 )
PHP에서 Swagger를 적용하면 코드보다 더 길은 주석을 보게 될 것이다.
물론 Phpstorm에 플러그인을 달면 좀 편하게 쓸 수는 있지만,
이러한 단순 노가다를 하면서, 우리는 한 번쯤 이런 생각을 한다.
( 뭐 자동화나 클래스로 하는 방법은 없을까? )
PHP 쪽에도 이러한 움직임이 아예 없지는 않다. 그중 필자가 추천하는 패키지는 아래와 같다.
https://vyuldashev.github.io/laravel-openapi/
필자가 해당 패키지를 선택한 이유
1. 문서 작성을 주석에 의존하지 않고 재활용이 가능했으면 좋겠다.
2. 커스텀이 자유로웠으면 좋겠다
위에 2가지가 모두 부합하여 선택하게 되었다.
적용 한 모습
적용 방법
1. 패키지 설치 (1)
// composer 설치
composer require vyuldashev/laravel-openapi
// config 파일 publish
php artisan vendor:publish --provider="Vyuldashev\LaravelOpenApi\OpenApiServiceProvider" --tag="openapi-config"
// 설치 제대로 되었는지 확인
php artisan openapi:generate
vyuldashev/laravel-openapi 패키지는 json 문서를 클래스로 파일로 관리하게 해 준다.
2. 패키지 설치 (2)
// L5-Swagger 패키지 추가
composer require "darkaonline/l5-swagger"
// config publish
php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"
vyuldashev/laravel-openapi 패키지는 json 파일을 생성해준다면, darkaonline/l5-swagger 패키지는 만들어진 json 파일을 읽어 화면이 뿌려주는 역할을 한다.
3. controller @method에 붙여보기
// controller 생성
php artisan make:controller TestController
[ProejctRoot]/app/Http/Controllers/TestController.php 생성된 Controller을 아래와 같이 수정해보자.
<?php
namespace App\Http\Controllers;
use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
#[OpenApi\PathItem]
class TestController extends Controller
{
/**
* 이 자리에 제목이 들어갑니다..
*
* 이 자리에 설명이 들어갑니다.
*/
#[OpenApi\Operation]
public function index()
{
}
}
중요한 것은 Controller 위에 #[OpenAPi\PathItem]
적용할 method 에 #[OpenApi\Operation]을 달아준다.
method의 경우 예제와 같이 제목과 설명이 들어가는 주석을 달아줘야지 에러가 나지 않는다.
[ProjectRoot]/routes/api.php 파일을 수정해보자
<?php
use App\Http\Controllers\TestController;
use Illuminate\Support\Facades\Route;
Route::get('test', [TestController::class, 'index']);
이제 적용된 것이다.
제대로 적용되었는지 json파일을 뽑아보자
php artisan openapi:generate > storage/api-docs/api-docs.json
이제 한번 브라우저에서 swagger의 경로에 들어가 보자
http://example.test/api/documentation
자신의 프로젝트 경로에 /api/documentation 에 들어가 보자.
경로는 config/l5-swagger.php 에서 바꿀 수 있다.
우리의 첫 swagger 가 완성되었다.
하지만 이렇게 작성하면 프론트 엔지니어에게 찍힌다.
보기 좋게 고도화를 해보자.
4. 고도화 (태그)
openapi의 설정 파일을 수정해 보자 config/openapi.php 에 있다.
collections.default.tags 에는 태그 배열이 들어간다 아래와 같이 고쳐보자.
'tags' => [
[
'name' => 'first-tag',
'description' => '첫 태그를 달아보았습니다.',
],
[
'name' => 'last-tag',
'description' => '마지막 태그를 달아보았습니다.',
],
],
그리고 아까 만들어 놓았던 TestController 도 수정해보자.
<?php
namespace App\Http\Controllers;
use App\OpenApi\Parameters\TestListParameters;
use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
#[OpenApi\PathItem]
class TestController extends Controller
{
/**
* 테스트 목록
*
* 어떠한 것들을 받아서 어떻게 처리한 후에 테스트 목록을 보여준다.
*/
#[OpenApi\Operation(tags: ['first-tag', 'last-tag'])]
// #[OpenApi\Parameters(factory: TestListParameters::class)]
public function index()
{
}
/**
* 테스트 상품 디테일
*
* 특정 테스트 항목을 자세히 보여준다
*/
#[OpenApi\Operation(tags: ['last-tag'])]
public function show()
{
}
/**
* 테스트 상품 생성
*
* 테스트를 생성한다
*/
#[OpenApi\Operation(tags: ['first-tag'])]
public function store()
{
}
}
show라는 method 가 추가되었으므로 [ProjectRoot]/routes/api.php 파일도 수정해보자
<?php
use App\Http\Controllers\TestController;
use Illuminate\Support\Facades\Route;
Route::get('test', [TestController::class, 'index']);
Route::get('show', [TestController::class, 'show']);
Route::post('test', [TestController::class, 'store']);
제대로 적용되었는지 json파일을 뽑아보자
php artisan openapi:generate > storage/api-docs/api-docs.json
이제 다시 브라우저에서 swagger의 경로에 들어가 보자
http://example.test/api/documentation
swagger에 태그가 생긴 것을 확인할 수 있다.
클릭해보면 설명도 제대로 들어간 것을 확인할 수 있다.
5. 고도화 (Parameters)
이제 입력받을 사항들을 넣어 보자.
터미널에 아래와 같은 명령어를 쳐서 파일을 생성한다.
php artisan openapi:make-parameters TestList
그럼 파일이 생성된다.
app/OpenApi/Parameters/TestListParameters.php
특이점은 우리가 입력한 클래스명 뒤에 Parameters 가 자동으로 붙어서 생성된다.
아래와 같이 수정해보자
<?php
namespace App\OpenApi\Parameters;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Parameter;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory;
class TestListParameters extends ParametersFactory
{
public function build(): array
{
return [
Parameter::query()
->name('name')
->description('(required) 이름을 입력')
->required()
->schema(Schema::string()),
Parameter::query()
->name('mobile')
->description('(optional) 전화번호를 입력')
->required(false)
->schema(Schema::string()),
];
}
}
return배열 안에 Parameter::query 하나당 하나의 Param이다.
schema 에는 자료형을 넣을 수 있는데 차후에 나오는 schema를 넣으면 모델 타입으로 한 번에 넣을 수도 있다.
이제 아까 만든 TestController에 적용해보자
<?php
namespace App\Http\Controllers;
use App\OpenApi\Parameters\TestListParameters;
use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
#[OpenApi\PathItem]
class TestController extends Controller
{
/**
* 테스트 목록
*
* 어떠한 것들을 받아서 어떻게 처리한 후에 테스트 목록을 보여준다.
*/
#[OpenApi\Operation(tags: ['first-tag', 'last-tag'])]
#[OpenApi\Parameters(factory: TestListParameters::class)] // <--
public function index()
{
}
/**
* 테스트 상품 디테일
*
* 특정 테스트 항목을 자세히 보여준다
*/
#[OpenApi\Operation(tags: ['last-tag'])]
public function show()
{
}
}
다시 json 파일을 생성하여 확인해보자
php artisan openapi:generate > storage/api-docs/api-docs.json
Parameters가 추가되었다.
6. 고도화 (Request Body)
모든 rest-api 가 GET 방식으로 데이터를 주고받는 것은 아니다, request body를 적용해보자.
아래와 같이 명령어를 입력해보자.
php artisan openapi:make-requestbody TestStore
파일이 다음과 같은 경로에 생성되었다
app/OpenApi/RequestBodies/TestStoreRequestBody.php
param 때와 마찬가지로 우리가 정해준 이름 뒤에 RequestBody 가 붙었다.
다음과 같이 수정해보자.
<?php
namespace App\OpenApi\RequestBodies;
use GoldSpecDigital\ObjectOrientedOAS\Objects\MediaType;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
use GoldSpecDigital\ObjectOrientedOAS\Objects\RequestBody;
use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory;
class TestStoreRequestBody extends RequestBodyFactory
{
public function build(): RequestBody
{
return RequestBody::create(self::class)
->description('테스트 생성')
->content(
MediaType::json()->schema($this->testSchema())
);
}
private function testSchema(): Schema
{
return Schema::object()->properties(
Schema::integer('id')->example(1)->title('테스트 아이디'),
Schema::string('name')->example('SPC-1')->title('테스트 상품 이름'),
Schema::array('examples')->items(
Schema::integer()->example(1),
),
)->required('id', 'name');
}
}
입력받는 부분 schema 부분이 재활용이 아쉬워 보일 것이다. 하지만 이 부분은 차후에 나오는 고도화 schema 부분에서
재활용이 가능하다.
TestController 에도 적용해보자
<?php
namespace App\Http\Controllers;
use App\OpenApi\Parameters\TestListParameters;
use App\OpenApi\RequestBodies\TestStoreRequestBody;
use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
#[OpenApi\PathItem]
class TestController extends Controller
{
/**
* 테스트 목록
*
* 어떠한 것들을 받아서 어떻게 처리한 후에 테스트 목록을 보여준다.
*/
#[OpenApi\Operation(tags: ['first-tag', 'last-tag'])]
// #[OpenApi\Parameters(factory: TestListParameters::class)]
public function index()
{
}
/**
* 테스트 상품 디테일
*
* 특정 테스트 항목을 자세히 보여준다
*/
#[OpenApi\Operation(tags: ['last-tag'])]
public function show()
{
}
/**
* 테스트 상품 생성
*
* 테스트를 생성한다
*/
#[OpenApi\Operation(tags: ['first-tag'])]
#[OpenApi\RequestBody(factory: TestStoreRequestBody::class)] // <---
public function store()
{
}
}
다시 json 파일을 생성하여 확인해보자
php artisan openapi:generate > storage/api-docs/api-docs.json
추가된 모습
7. 고도화 (Response)
이번에도 명령어로 cli 시작한다.
php artisan openapi:make-response Test
생성은 다음과 같은 경로에 생성된다.
app/OpenApi/Responses/TestResponse.php
이번에도 우리가 작성한 이름 뒤에 Response 가 붙어서 생성되었다.
이제 파일을 다음과 같이 수정해보자.
<?php
namespace App\OpenApi\Responses;
use GoldSpecDigital\ObjectOrientedOAS\Objects\MediaType;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Response;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory;
class TestResponse extends ResponseFactory
{
public function build(): Response
{
$response = Schema::object()->properties(
Schema::integer('status_code')->example(200),
Schema::string('message')->example('테스트 상품 등록 완료'),
);
return Response::create(self::class)
->description('테스트 상품 등록')
->content(MediaType::json()->schema($response));
}
}
이번에도 역시 TestController에 적용해보자.
<?php
namespace App\Http\Controllers;
use App\OpenApi\Parameters\TestListParameters;
use App\OpenApi\RequestBodies\TestStoreRequestBody;
use App\OpenApi\Responses\TestResponse;
use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
#[OpenApi\PathItem]
class TestController extends Controller
{
/**
* 테스트 목록
*
* 어떠한 것들을 받아서 어떻게 처리한 후에 테스트 목록을 보여준다.
*/
#[OpenApi\Operation(tags: ['first-tag', 'last-tag'])]
// #[OpenApi\Parameters(factory: TestListParameters::class)]
public function index()
{
}
/**
* 테스트 상품 디테일
*
* 특정 테스트 항목을 자세히 보여준다
*/
#[OpenApi\Operation(tags: ['last-tag'])]
public function show()
{
}
/**
* 테스트 상품 생성
*
* 테스트를 생성한다
*/
#[OpenApi\Operation(tags: ['first-tag'])]
#[OpenApi\RequestBody(factory: TestStoreRequestBody::class)]
#[OpenApi\Response(factory: TestResponse::class)] // <--
public function store()
{
}
}
적용된 모습
response는 다음과 같이 여러 개도 적용 가능하다.
8. 고도화 (Schema)
마지막이다 조금만 더 힘내자.
다음과 같이 cli 명령을 입력하자
php artisan openapi:make-schema Test
다음과 같이 파일이 생성되었다. app/OpenApi/Schemas/TestSchema.php
이번에는 우리가 입력한 글자 뒤에 Schema가 생겼다.
이번에는 아까 request body에서 생성했던, schema를 잘라와서 붙여 넣어 보자
<?php
namespace App\OpenApi\Schemas;
use GoldSpecDigital\ObjectOrientedOAS\Contracts\SchemaContract;
use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema;
use Vyuldashev\LaravelOpenApi\Contracts\Reusable;
use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory;
class TestSchema extends SchemaFactory implements Reusable // <-- 이 인터페이스 꼭 넣어주세요
{
public function build(): SchemaContract
{
return Schema::object()->properties(
Schema::integer('id')->example(1)->title('테스트 아이디'),
Schema::string('name')->example('SPC-1')->title('테스트 상품 이름'),
Schema::array('examples')->items(
Schema::integer()->example(1),
),
)->required('id', 'name');
}
}
아까 전에 생성했던 TestStoreRequestBody를 수정해보자
<?php
namespace App\OpenApi\RequestBodies;
use App\OpenApi\Schemas\TestSchema;
use GoldSpecDigital\ObjectOrientedOAS\Objects\MediaType;
use GoldSpecDigital\ObjectOrientedOAS\Objects\RequestBody;
use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory;
class TestStoreRequestBody extends RequestBodyFactory
{
public function build(): RequestBody
{
return RequestBody::create(self::class)
->description('테스트 생성')
->content(
MediaType::json()->schema(TestSchema::ref()) // <--
);
}
}
다시 json 파일을 생성하여 확인해보자
php artisan openapi:generate > storage/api-docs/api-docs.json
바뀐 부분이 없을 것이다. schema를 활용하면 모델 단위로 재활용이 가능하다.
9. 마무리
소개한 기능 외에도 인증, schema의 고도화 등등 많지만 이 부분은 매뉴얼이 생각보다 불친절해서 고생 좀 했었다.
독자들은 나와 같은 문제가 없기를 바라며 질문 사항을 댓글에 달아주시면, 아는 선에서 답변해주겠다.
지루한 글 읽어줘서 고맙습니다.
ps..
오늘 소개한 라이브러리 말고도 후보에는 rakutentech/laravel-request-docs 패키지도 있다.
request와 resource 만 잘 써도 코드의 주석은커녕 첨부 없이도 자동으로 완성된다는 장점이 있지만,
설명글 및 태그를 커스텀할 수 없어서 후보에서 제외되었다. 하지만 독자들 중에는 필요한 사람이 있을지 몰라서 글을 남긴다.
'개발 > Composer 추천' 카테고리의 다른 글
Laravel 추천 패키지 (0) | 2023.02.17 |
---|---|
Laravel에 Modern 하게 DTO 사용하기 (feat: 라라벨 스프링) (0) | 2022.12.14 |
라라벨 개발시 설치하면 좋은 composer 리스트 (0) | 2018.12.04 |
라라벨 이미지 처리 (0) | 2018.09.04 |
라라벨 개발 도우미 (0) | 2018.09.04 |