서버개발자가 되는법 - #12 API 공유를 위해 Swagger(스웨거) 사용하기. Django에서 Swagger 사용하기

     

목차 - 2020/09/29 - [Study/서버] - 서버개발자가 되는법 - 목차

 

유튜브 - 

 

git - tkdlek11112/server_dev at 서버개발자_12 (github.com)

 

 

 

들어가기 전에

 

이번 포스팅에서는 Swagger(스웨거)를 통해 우리가 만든 Rest API를 공유하는 방법을 배워보겠습니다. 개발을 하면서 개발보다는 문서작업을 많이 하는 단계가 있는데, 처음에 클라이언트와 Interface를 협의할 때가 바로 그때입니다. 우리는 To-Do 앱을 만들어보면서 Input과 Output을 정의하는 과정을 체험해봤습니다. 그때는 그냥 제가 화면에 Input을 명시해주고 여러분이 서버 쪽 API를 만드는 방식으로 진행되었죠.

 

하지만 보통은 서버쪽에서 리드를 하게 됩니다. 서버 개발자들이 만드니까 당연한 거겠죠? ㅋㅋ 서버에서 API를 어느 정도 만들었으면 만든 API에 대한 정의서 혹은 명세서를 클라이언트에게 전달해주게 됩니다. 이 때 전달하는 형태는 여러 가지가 있을 수 있는데, 엑셀을 사용하는 곳이 있고, PDF나 word를 사용하는 곳이 있습니다. Postman으로 만들어서 export 해서 주는 곳도 있고요. 보통 이 문서의 형태는 여러분들이 open API를 사용해 봤다면 거기서 제공하는 명세서와 비슷합니다. 

 

카카오 로그인 API

 

하지만 서버개발자 입장에서 이러한 문서를 만드는 작업은 리소스가 많이 소모됩니다. 코드로도 만들고 문서로도 작업해야 되니 힘들죠. 클라 입장에서도 이렇게 온 문서를 읽고 데이터가 어떻게 오는지 테스트해보기가 불편합니다.

 

이런 불편함들을 해소시켜줄 수 있는 툴이 바로 Swagger입니다. Swagger를 간단하게 설명하면 "내가 만든 API를 문서화해주고 테스트해볼 수 있는 툴"입니다. 

 

이번 포스팅에서는 Django에 Swagger를 설치해보고 어떻게 사용하는지를 알아보겠습니다.

 

 

 

Django 프로젝트에 적용하기

 

적용해볼 프로젝트는 여태까지 저희가 만들었던 To-Do앱으로 할 예정입니다. 생각보다 아주 아주 아주 간단하게 swagger를 설치할 수 있습니다. 'drf-yasg' 패키지를 설치하면 되는데요, Django에 swagger를 적용하는 패키지가 여러 개가 있는데 현재 잘 되는 건 drf-yasg 뿐인 것 같습니다.

 

 

pip install drf-yasg

 

이것 저것 깔림

 

그리고 settings.py에 INSTALLED_APP에 drf-yasg를 추가합니다.

 

drf_yasg 추가

 

그 다음 settings.py와 같이 있는 urls.py를 다음과 같이 고쳐줍니다.

 

from django.contrib import admin
from django.urls import path, include
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework.permissions import AllowAny

schema_view = get_schema_view(
    openapi.Info(
        title="TO-DO API",  # 타이틀
        default_version='v1',   # 버전
        description="서버개발자가 되는법 #12",   # 설명
        terms_of_service="https://cholol.tistory.com/551",
        contact=openapi.Contact(email="mychew@kakao.com")
),
    validators=['flex'],
    public=True,
    permission_classes=(AllowAny,)
)


urlpatterns = [
    # swagger
    path(r'swagger(?P<format>\.json|\.yaml)', schema_view.without_ui(cache_timeout=0), name='schema-json'),
    path(r'swagger', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path(r'redoc', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc-v1'),
    # django
    path('admin/', admin.site.urls),
    path('login/', include('login.urls')),
    path('todo/', include('todo.urls')),
]

 

schema_view를 설정하고 urlpatterns에 path 3개를 추가했습니다. 이제 준비가 끝났습니다.

 

~/swagger로 접속해볼까요

 

우앗?

 

공통부분 설정만 했는데 아래 보면 login과 todo api들이 보입니다. Awssome!!

 

하지만 아직은 빈 껍데기입니다. API들을 클릭해서 눌러보면 안에 아무 내용이 없습니다.

 

텅텅

 

이제 옵션을 줘서 하나씩 추가해봅시다. 먼저 조회부터.

 

API를 누르고 오른쪽에 Try it out을 누르면 Postman처럼 API를 호출해볼 수 있습니다. 다른 API들은 입력값이 있어야 하지만 select의 경우 입력값이 없어도 되기 때문에 한번 해보겠습니다.

 

execute를 누르면 실행됨

 

그럼 저희가 TO-DO앱을 만들었을때 내용들이 담겨있습니다. 만약 아무것도 없다면 빈 값이 나올 수도 있겠죠? 

 

이제 Create를 해보기 위해 swagger에 create api에 대한 정보가 나오도록 소스에 추가해보도록 하겠습니다.

 

class TaskCreate(TodoView):
    @swagger_auto_schema(tags=["TO-DO 생성"], request_body=TodoSerializer, query_serializer=TodoSerializer)
    def post(self, request):
        # 이전버전 호환을 위해 헤더먼저 검사하고 body로 내려감.
        print('헤더 id', self.user_id,'헤더 version', self.version)
        ...

 

추가된 부분이 보이시나요? @swagger_auto_schema 한 줄을 추가했습니다. 안에 몇 가지 옵션을 넣었는데, tags는 swagger에서 해당 API가 어떻게 표기되는지를 결정합니다. 신기하게 리스트로 값을 넣어줘야 합니다. ㅎㅎ

 

이름 변경

 

request_body랑 query_serializer는 swagger에서 해당 api의 인풋 값을 보거나 실제로 api를 호출할 때 입력 필드를 정의해 주는데요 기본적으로 serializer형태로 들어가야 합니다. 아쉽게도 우리가 만든 To-Do앱은 Serializer를 사용하지 않았기 때문에 새로 만들어줘야 하는데, 만약 Serializer를 사용하셨다면 그냥 넣으시면 됩니다. ㅎㅎ 저는 아래와 같이 TodoSerializer를 만들었습니다.

 

class TodoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = ['user_id', 'name']


class TaskCreate(TodoView):
    @swagger_auto_schema(tags=["TO-DO 생성"], request_body=TodoSerializer, query_serializer=TodoSerializer)
    def post(self, request):
        # 이전버전 호환을 위해 헤더먼저 검사하고 body로 내려감.
        print('헤더 id', self.user_id,'헤더 version', self.version)
        ...

 

Serializer안에 fields에는 실제 API에 사용되는 input필드를 넣어줍니다. Create 할 때는 사용자 id와 Task 이름만 있으면 됩니다. 이제 swagger가 어떻게 바뀌었는지 한번 볼까요?

 

뭔가 정보가 늘어났습니다!!

 

이거를 보면 아~ 이 API는 어떤 input을 입력해야 하는구먼~ 하고 알게 됩니다. Try it out을 통해 실제로 값을 집어넣어서 실행할 수 있습니다.

 

테스트할 때 json 형태로 넣어야 합니다 ㅎㅎ 바로 아래 있는 곳에 입력하는 게 아니에요~!

 

200 응답~!

 

To-Do Create가 성공하면 To-Do의 id값을 주도록 해놨었는데 id가 잘 왔네요!! select API를 호출해서 바로 확인 가능합니다.

 

바로 값이 들어간것이 확인된다.

 

Swagger를 통해서 응답 코드에 대한 정의도 할 수 있습니다.

 

class TaskCreate(TodoView):

    @swagger_auto_schema(tags=["TO-DO 생성"],
                         request_body=TodoSerializer,
                         query_serializer=TodoSerializer,
                         responses={
                             200: 'TO-DO 생성 완료',
                             403: '인증에러',
                             400: '입력값 유효성 검증 실패',
                             500: '서버에러'
                         })
    def post(self, request):
        # 이전버전 호환을 위해 헤더먼저 검사하고 body로 내려감.
        print('헤더 id', self.user_id,'헤더 version', self.version)
        if self.user_id:
        ...

 

위와 같이 responses 옵션을 추가하고 각 http코드 별로 메시지를 정의하면...?

 

Responses에 대한 정의 완료

http코드뿐만 아니라 응답 필드들도 정의할 수 있습니다. Create가 성공할 경우 id값이 오기 때문에 id를 추가해볼게요.

 

 

class TaskCreate(TodoView):
    id_field = openapi.Schema(
        'id',
        description='To-Do가 생성되면 자동으로 채번되는 ID값',
        type=openapi.TYPE_STRING
    )

    success_response = openapi.Schema(
        title='response',
        type=openapi.TYPE_OBJECT,
        properties={
            'id': id_field
        }
    )

    @swagger_auto_schema(tags=["TO-DO 생성"],
                         request_body=TodoSerializer,
                         query_serializer=TodoSerializer,
                         responses={
                             200: success_response,
                             403: '인증에러',
                             400: '입력값 유효성 검증 실패',
                             500: '서버에러'
                         })
    def post(self, request):
        # 이전버전 호환을 위해 헤더먼저 검사하고 body로 내려감.
        ...

 

id_field와 success_response 두 개를 추가하고 auto_schema에 옵션으로 넣었습니다. 결과는...?

 

이제 클라이언트 개발자가 "아 입력으로 이걸 넣으면 출력으로 이게 오는구먼?" 하고 알 수 있게 되었습니다. 

 

물론 서버 개발자가 이것저것 많이 추가해줘야 하지만... 문서를 따로 만드는 것보다는 개발자스럽지 않나요? ㅋㅋㅋ

 

요렇게 뭐 만들지 않고 마크다운 형식으로 swagger에 정보를 추가할 수 있습니다.

 

class TaskCreate(TodoView):
    '''
        여기에 주석으로 뭔가 쓰면 swagger에 반영됩니다.
        ---
        # TO-DO를 생성할 때 사용하는 API
            - user_id : 사용자 ID
            - name : To-Do 이름
    '''

    id_field = openapi.Schema(
        'id',
        description='To-Do가 생성되면 자동으로 채번되는 ID값',
        type=openapi.TYPE_STRING
    )

    success_response = openapi.Schema(
        title='response',
        type=openapi.TYPE_OBJECT,
        properties={
            'id': id_field
        }
    )

    @swagger_auto_schema(tags=["TO-DO 생성"],
                         request_body=TodoSerializer,
                         query_serializer=TodoSerializer,
                         responses={
                             200: success_response,
                             403: '인증에러',
                             400: '입력값 유효성 검증 실패',
                             500: '서버에러'
                         })
    def post(self, request):
        # 이전버전 호환을 위해 헤더먼저 검사하고 body로 내려감.
        ....

 

Class 아래 공간에 주석을 추가하면 swagger에 자동으로 반영됩니다. 마크다운이 먹기 때문에 다양한 정보를 표현 가능합니다.

 

더 멋있어짐 ㅎ

 

이런 식으로 모든 API에 대한 정보를 정의하고 클라이언트한테 자 여기 I/O 명세서 ~ 하면서 URL 던져주면 여러분은 멋진 서버 개발자가 될 수 있습니다.

 

 

정리하면서

 

이번 포스팅에서는 API를 손쉽게 공유할 수 있는 Swagger를 사용해봤습니다. 개발자는 개발 말고도 다른 작업들이 많은데, 그중에서 문서작업을 정말 쉽게 해주는 Tool입니다. 개발자들과 커뮤니케이션 코스트도 낮아지고요. 실제로 현업에서는 많은 개발자들과 일하게 되고 회의하는 시간이 개발하는 시간보다 많을 수 있는데, 이런 효과적인 도구를 사용해서 시간을 단축할 수 있습니다. 물론 모든 개발자가 사용법을 알아야겠지만요 ^^ 그렇기 때문에 개발자에게 학습은 중요한 것 같습니다.

 

혼자 토이 프로젝트를 진행하거나 다른 분들과 사이드 프로젝트를 할 때 Swagger를 이용해 보세요! Django 말고 다른 프레임워크에도 Swagger를 적용할 수 있습니다. 이번 포스팅에서 Django로 Swagger를 배웠다는 것에 중점을 두지 말고, 개발을 도와주는 이런저런 Tool이 있고, Swagger로 API 문서화를 손쉽게 할 수 있다는 것에 중점을 두세요~! 언어와 프레임워크 역시 도구에 지나지 않습니다!! ㅎㅎ

 

그럼 오늘은 여기까지~~ 수고하셨습니다.

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY