작년에 SI 업무를 반년간 진행하면서 화나는점도 많았지만, 돌이켜보면 여러모로 배운것도 많이 있었다.
그중 하나가 스웨거였는데, 이전까지는 스웨거를 따로 사용하지 않고 단순히 REST API 문서를 만들어서 query_params
, reuqest_body
, response_body
등을 적어서 개발팀끼리 공유했었는데 수기로 작성하려니 여간 불편했던점이 한두가지가 아니었다.
그러다가 SI업무를 진행하면서 Django에도 자동으로 API문서화가 있다는걸 알게되었다.
그때 당시에 스웨거를 도입하면서 알게된 내용들에 대해서 정리하고, Django 내에 설정하는 방법을 작성해보도록 하겠다.
우리가 API를 만들게되면 프론트엔드 개발자와 소통하면서 이러이러한 API가 추가되었고, request url, method, response_body, request_query_params 등등에 대해서 공유해주어야 프론트엔드 개발자는 그것을 통해 API를 연동하고 실제 서버에서 데이터를 불러 올 수 있다.
이 과정에서 수기로 전달하거나 말로 전달하기에는 너무 빡빡하기도 하고, 이러한 방식으로 전달하게되면 아무래도 사람이 직접적으로 하는 내용이다 보니 소통간에 잘못 전달되는 경우가 있을 수 있다.
그러한것들을 예방하고자 Swagger라는것을 통해 API 문서 자동화를 이끌어 낼 수 있다.
우리가 개발하면 개발하는 내용 그대로 모든 내용들이 자동으로 문서화가 되어 우리가 굳이 설명하거나 문서로 전달하지 않더라도 프론트엔드 개발자 혹은 다른 개발자들이 API 명세를 확인할 수 있는 것이다.
API 명세 뿐 아니라, API에 대한 목업(Mock-up) 테스트도 지원을 하기 때문에, 프론트엔드와 연동을 하지 않을 상태에서도 Response를 확인해볼 수 있는 테스트를 진행해 볼 수 있다는것도 강점이다.
방법으로는 두가지가 있는데, SwaggerHub라는 Swagger를 만든 곳의 Cloud를 이용해서 직접 관리하는 방법이 있고, 각자 회사의 서버에 직접 Swagger 모듈을 도입하여 적용하는 방법이 있는데, 나는 그중에서 후자의 방법에 대해 이야기하고자 한다.
Django에서 지원하는 여러가지 Swagger 모듈이 있는데 그중에서 가장 대표적인 drf-yasg
를 사용했다. drf-yasg는 장고로 정의된 API를 문서화할 수 있는 패키지로, (django rest framework- Yet another Swagger generator)의 약자이다.
설치를 하기전에 django-rest-framework
도 설치가 되어있어야한다. 우리가 사용하는 것은 drf-yasg
. 즉 drf 환경 위에서 동작하도록 되어있기때문에 설치가 필요하다.
아마 Django로 REST API를 만드는 사람들이라면 거의 설치가 되어있겠지만, 만약 처음 프로젝트를 시작할 때 부터 도입하고자 하는 분이라면 django-rest-framework
패키지도 추가로 설치하도록 한다.
pip install drf-yasg
pip install djangorestframework
만약 pip로 설치가 제대로 되지않는 경우에는 pip3
처럼 버전을 정확하게 명시하는 명령어를 사용하여 시도하면 설치가 정상적으로 될 것이다.
모듈을 설치했다면 Django 내에 있는 settings.py
파일 안에 환경설정을 추가 해준다.
첫번째는 아래와 같이 INSTALLED_APPS
항목 안에 추가해주도록 하자.
INSTALLED_APPS = [
... # another apps
'drf_yasg', #drf_yasg
'rest_framework', #djangorestframework
... # another apps
]
다음으로는 urls.py
에서 우리가 일반적인 API처럼 특정 URL을 통해 Swagger 문서에 접속할 수 있도록 설정하는 과정이다.
from drf-yasg.views import get_schema_view
from drf-yasg import openapi
...
schema_view = get_schema_view(
openapi.Info(
title="Your Server Name or Swagger Docs name",
default_version="Your API version(Custom)",
description="Your Swagger Docs descriptions",
# terms_of_service="https://www.google.com/policies/terms/",
# contact=openapi.Contact(name="test", email="test@test.com"),
# license=openapi.License(name="Test License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
import
를 통해 drf-yasg
를 임포트하여 get_schema_views라는 메서드를 가져와 설정한다. openapi
는 앞으로 Swagger에서 자주쓰게 될 내용이다. 이녀석이 api에 대한 명세를 작성하는것을 도와주는 역할을 한다.
다음으로는 Swagger를 보기위한 URL설정을 추가해주면 된다.
urlpatterns = [
# other user API end-point URL
...
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view_v1.without_ui(cache_timeout=0), name='schema-json'),
url(r'^swagger/$', schema_view_v1.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view_v1.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
위처럼 설정하게되면 모든 환경에서 스웨거를 접속할수도 있게 되는데 urlpatterns에 있는 url은 변경이 가능해서 각각의 개발환경마다 접속되는 스웨거를 다르게 설정 할 수도 있다.
우리의 경우 아래와 같이 서버실행시에 실행환경이 DEV인경우라면 개발 환경의 Swagger를 보여주도록 하고있다.
해당 설정은 디버그일때만 swagger 문서가 보이도록 해주는 설정이라는 데, urlpath도 이 안에 설정 가능해서, debug일때만 작동시킬 api도 설정할 수 있다.
# 서버 동작 환경이 개발서버인 경우 개발서버 Swagger 접속시 운영 서버의 Swagger가 아닌 개발서버 기준의 Swagger를 노출시킴
if settings.DEPLOY_SERVER_TYPE == 'dev':
urlpatterns += [
re_path(r'^v1/dev/swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
name="schema-json"),
re_path(r'^v1/dev/swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^v1/dev/redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
Swagger를 보기 위한 설정은 모두 끝났고, 이제 우리가 개발한 API를 스웨거가 인식하고 볼 수 있도록 추가하면 된다.
첫번째는 API URL 설정이다. 우리가 API를 호출하기위해 설정한 end-point
를 urls.py
안에 지정해주면 된다.
CBV(Class-Based-View)로 개발한 경우와 FBV(Funtion-Based_View) 방식으로 개발한 경우에 URL 설정 방법이 다르기 때문에 아래 코드를 참고해서 각자가 개발한 방법에 맞게 URL을 지정하면 될 것 같다.
# If Using Class-Based-View
urlpatterns = [
path('/users/<user_guid>', VwUserControlClass.as_view({"get": "get_user_info"})),
path('/users/<user_guid>/modify', VwUserControlClass.as_view({"put": "update_user_info"})),
]
# If Using Function-Based-View
urlpatterns = [
path('/users/<user_guid>', get_user_info),
path('/user/<user_guid>/modify', update_user_info)
]
@Swagger Auto Schema
란, 스웨거가 API에 대한 내용을 문서화 시켜주는 기능인데, 두가지 방법이 있다.
DRF를 사용하는경우에 Serializer
를 통해 파라미터등을 지정하여 scheme를 추가하는 방법
DRF를 통해 모델이라던가 함수에 대해서 Serializer
를 활용하고 있는 개발자라면 해당 방법이 깔끔하고 좋다. drf-yasg
자체가 DRF를 통해 동작하다보니 공식적으로도 Serializer
를 통해 자동 포맷 시키는걸 권장하고 있기도 하다.
파라미터나 리퀘스트 바디등을 제외한 나머지 부분은 2번과 동일하게 작성해주어야한다.
@swagger_auto_schema
를 사용해서 개발자가 직접 해당 API에 대해 docs를 작성하는 방법
1번의 방법과 비슷하지만, manual_parameter
부분과 request_body
, query_parameter
모두 auto_schema 안에 전부 작성해주는 방법이다.
1번 2번 차이는 이정도 일 듯하다.
1번의 방법을 사용하면 비즈니스로직만 분포한 곳에 조금 더 깔끔하게 스웨거 오토 스키마를 작성 가능하다는 장점이 있지만, 어떠한 파라미터가 있는지는 시리얼라이저를 통해서 확인해야하는 단점이 존재한다.
2번방법을 사용한다면 전체적인 모든 내용을 한번에 볼 수 있지만, 스웨거 오토 스키마로 인해 비즈니스 로직이 남긴 파일들이 과도하게 길어지고 헷갈릴 수 있다는 단점이 존재한다.
편한 방법으로 하면 될 듯? (나는 2번 방법으로 하다가 최근에 로직들이 많아지다보니, 1번 방법으로 전환 중에 있다)
1번에 관련한 시리얼라이저 적용 방법은 참고한 블로그 링크를 아래에 걸어두었으니 1번방법을 사용할 사람들은 참고해봐도 좋을 듯 하다.
@swagger_auto_schema(
operation_description="회원관리_유저 정보 조회",
operation_summary="회원관리_유저 정보 조회",
operation_id='메인_회원관리_01',
tags=['메인_회원관리'],
manual_parameters=[Authorization],
query_serializer=ManagementUserSerializer,
responses={
... 중략
API 맨 위에 이런식으로 작성을 하게 될 텐데, 오토 스키마 사용을 위해서는 항상 @swagger_auto_schema
데코레이터를 붙여 주고 시작해야한다.
operation_description
API 설명 부분이다. API에 대한 설명을 작성하면 됨.
operation_summary
API 간단한 타이틀 혹은, 통합하는 주제를 적는부분
operation_id
API를 스웨거에서 구분하는 고윳값이라고 생각하면 된다. 이 부분에서 operation_id가 겹칠 경우 swagger 상에서 가장 먼저 나온 API만 출력하여 겹쳐 보이거나, 서로 다른 API가 동일한 operation_id를 가지고 나타날 수 있기 때문에 신경을 써주어야한다.
tags
하나의 그룹핑화를 할 수 있는 곳이라고 보면된다. 예를들어 위와 같이 회원관리와 관련된 API들을, 메인_회원관리
로 묶었을 때 swagger 상에서는 회원관리 탭이 생겨 그 탭을 눌러서 확장시키면 해당 태그들을 가진 API들을 모아서 볼 수 있다.
manual_parameters
여기서 query_params
, request_header
(token 등 헤더에 포함되는 정보들)와 같은 곳에 들어가는 내용들을 작성해 줄 수 있는데 위에 설명한 2가지 방법에 따라 작성 방식이 다르다.
1번 방법으로 했을 경우 아래와 같이 query_serializer
라는 곳에 시리얼라이저를 지정해야하고, 헤더는 이곳에 작성해야한다.
2번 방법인 경우에는 query_params
, request_header
모두 @swagger 시작전에 사용할 파라미터와 헤더들을 선언을 해주고 manual_parameters
부분에 작성해주면 된다.
query_serializer / request_body
쿼리파리미터, 리퀘스트 바디와 같은 내용들을 작성하는 곳이다.
시리얼라이저를 사용하는 경우에는 본인이 작성한 시리얼라이저로 기입해주면 되고, 그게 아니라면 query_serializer
는 위에 있는 manual_parameters
에, request_body
는 response
처럼 동일하게 작성해주면 된다.
response
API의 응답값의 Mock-up
형태를 작성해주면 된다.
response_body
나 request_body
의 작성방법 같은 경우에는 swagger 공식문서에 잘 공유되어있으니 참고해서 필요한대로 작성하면 될 것 같다.
설정이 모두 완료되었다면 아래와 같이 http://127.0.0.1:8000
에 접속하여 확인 할 수 있다.
로컬 주소의 경우에는 각자 사용하는 포트 번호가 다를 것이니 확인하여 접속하도록 하자.
Swagger를 알기전에는 정말 구글 스프레드 시트에 일일이 기록하여 작성하고 post man으로 테스트한 결과를 붙여서 넣고 프론트 작업자 분들은 그걸 가지고 mock-up 테스트를 진행하고 하는 정말 불편한 방식으로 진행했었다.
아마 그당시에는 회사가 완전 시드단계였고, Django를 이제 막 시니어분들께서도 접한 상태이시다보니 빠른 개발에 치우쳐 그랬던 듯하다.
하지만 Swagger를 알게 된 이후로 API 문서화도 백엔드 개발단계에서 모두 이루어지고, 프론트 개발자 분들도 우리가 올려놓은 Swagger를 통해 mock-up 테스트도 진행하고 response-body, request-body, query-parameter등도 손쉽게 확인 할 수 있게 되어 더욱 스피드하고 정교한 개발이 가능하게 되었다.
아마 대기업들은 다 사용하고 있을거라 생각하지만, Swagger라는것을 일하면서 처음 보고 사용을 하고 있는 나로써는 굉장히 편리하다고 생각하고 있기때문에 앞으로도 더 편하고 원활한 개발을 위해서 적극적으로 사용해야 겠다는 생각이 들었다.
Swagger Documents
https://swagger.io/docs/specification/2-0/basic-structure/
Django + Swagger 기본 사용법
https://velog.io/@max-sum/Django-Swagger-%EA%B8%B0%EB%B3%B8%ED%8E%B8#%EF%B8%8E-body