DaeHyun Baek
타운컴퍼니 기술블로그
11 min readSep 17, 2018

--

친절하게 Django REST framework API 문서 자동화하기 (drf-yasg)

안녕하세요. R&D 파트의 백대현입니다.

소프트웨어 프로젝트를 진행하면서 요구사항 명세서, 스토리 보드, 설계 문서, 일정관리 계획서, API 문서 등 프로젝트를 수행하는 규모와 방식에 따라 각기 다른 목적으로 다양한 문서를 작성하게 됩니다. 수 많은 프로젝트에서 그렇듯 이런 문서는 조금만 방심하면 유지보수 되지 않는 문서가 되곤 합니다.

프로젝트 일정이 급해서 / 문서의 중요도가 낮아져서 / 구두로 공유가 된 내용이라서 / 깜빡하고 문서 업데이트를 잊어버려서 / (귀찮아서)

여러가지 이유로 유지보수 되지 않는 문서로 인해 발생하는 유산(legacy)은 가끔(거의 항상) 프로젝트에 악영향을 주곤 합니다. 그 중에 API 문서에 대해 공유해보려 합니다.

일단 Django REST Swagger

할 일이 많다고 엄살피우는 바쁜 백엔드 개발자(저)는 빠르게 진행되는 프로젝트에서 문서를 만들고 유지보수할 자신이 없다는 핑계로 API 문서를 자동화하기로 했습니다. 다행히 타운어스 서비스의 백엔드로 사용하는 Django의 DRF(Django REST framework)에서는 많은 문서화 툴을 제공합니다.(http://www.django-rest-framework.org/topics/documenting-your-api/)

처음에는 익숙한 swagger (Django REST Swagger)를 사용했습니다. swagger는 자동으로 API 목록과 각 API의 Request Body, Query Parameter를 문서화해주며 바로 Postman과 같이 API를 테스트해 볼 수 있는, 많은 프로젝트에서 사용하는 검증된 문서화 도구입니다.

Django REST Swagger를 사용하다 보니 몇가지 불편한 점이 있었습니다.

1. response schema를 제공하지 않음

Build-in API documentation과 마찬가지로 Django REST Swagger가 의존하고 있는 CoreAPI에서 Response Schemas를 아직 대응하고 있지 않아 Response를 각 API 호출을 통해 확인해야 하는 불편함이 있습니다.

2. Field-level documentation이 어려움

CoreAPI 기반에서는 Request / Response 각 필드에 대한 documentation이 어렵습니다. 각 필드의 description, validation condition, choices 등이 구체적이고 명확하게 설명되어야 독자(프론트엔드 개발자)가 API에 대해 몇번씩 물어보는 상황이 생기지 않습니다. (귀찮았다는건 아니다…)

3. Response의 Object를 판별하기 어려움

특히 Response의 경우 string, int으로만 반환되기 때문에 nested schemas의 경우 각 Object를 파악하기 불편합니다. Django REST Swagger에서는 아래와 같이 확인해야 합니다.

Request를 보내고 Response Body를 확인해야한다

특히 Angular에서 아래와 같이 DRF의 Serializer를 Interface Model로 정의하여 사용하기 때문에 타입을 명확하게 전달할 필요가 있습니다.

Django의 Serializer
Angular의 Model

직접 만들..(읍읍), 다른 걸 찾아보자 !!

API 문서에 Response도 있어야하고, 구체적이고 명확하게 설명도 가능한 문서화 툴을 찾아보기 시작했습니다.

API Blueprint

https://apiblueprint.org/
유연하고 깔끔한 마크다운 기반 Web API language. HTTP Testing Framework 인 Dredd를 사용하여 Auto Testing 이 가능합니다. (작성된 API Document 을 수시로 Testing하여 Document 의 Integrity 유지 가능) 다 좋은데 직접 문서 유지보수를 해야하기에 손목 건강을 생각해서 선택하지 않았습니다.

API Blueprint

Apiary

https://apiary.io/
API Blueprint의 SaaS 버전입니다. Mock Server, Github Sync, 팀 협업 등 제공하는 편의성 툴도 많고 깔끔하고 편해보이지만 private은 유료인데다가 ORACLE CLOUD.. 상당히 비쌉니다... :(

스타트업은 울지요…

RAML

https://raml.org/
YAML 문법과 유사한 RAML 언어를 사용, Atom 기반으로 Workbench를 제공합니다. 역시 직접 문서 유지보수를 해야합니다.

drf-yasg

https://github.com/axnsan12/drf-yasg
이 프로젝트를 처음 발견했을 때 이제 막 시작한 프로젝트였습니다. Django REST Swagger의 CoreAPI 기반으로 인해 생기는 불편함을 해결하기 위해 Swagger/OpenAPI 2.0 기반으로 작성된 DRF용 문서 자동화 라이브러리 입니다. 아래와 같은 특징이 있습니다.

  • nested serializer와 schema 대응
  • response schema 및 field-level description 가능
  • swagger-spec-validator 혹은 flex로 schema validation 가능
  • Versioning 가능
  • Swagger-UI / Redoc 활용 가능

drf-yasg setup

처음에 도입할때는 공식문서가 설명이 부족한 부분이 많았는데 지금은 비교적 친절하게 문서가 제공됩니다. (https://drf-yasg.readthedocs.io/en/stable/)

공식문서에서 제공하는 설치 절차는 아래와 같습니다.

$ pip install -U drf-yasg

settings.py의 INSTALLED_APPS에 추가

INSTALLED_APPS = [
...
'drf_yasg',
...
]

urls.py에 아래와 같이 추가

...
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

...

schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
validators=['flex', 'ssv'],
public=True,
permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
...
]

위와 관련된 추가적인 자세한 사항은 공식문서를 참조해주시기 바랍니다.

그래서 이렇게 쓰고있습니다 :)

타운어스의 API 문서는 내부 개발팀 /외부 파트너사를 위한 API 문서로 나뉘어 제공되고 있습니다. 이를 위해 아래와 같이 schema_view를 나눠 관리하고 있습니다.

내부 개발팀을 위한 API 문서는 localhost에서만 확인할 수 있도록 DEBUG=True 일 경우에만 보이도록 했고, 파트너사를 위한 API 문서는 Public 경로로 접속할 수 있도록 합니다.

이 정도의 설정만으로도 충분히 쓸 만한 자동화된 API 문서를 얻을 수 있습니다.

Redoc UI
Swagger UI

위와 같이 Django REST Swagger에서 제공하지 못한 nested serializer와 schema, response schema 및 field-level description이 모두 가능해졌습니다.

nested serializer가 있을 경우 자동으로 schema가 인식이 되며, Serializer의 label과 help_text, Model의 verbose_name이 각 Field-level Description이 됩니다.

이제 문서화 만을 위한 별도의 시간과 노력 없이 자연스럽게 쓸 만한 API 문서를 자동으로 만들 수 있습니다.

조금 더 욕심을 부려서

error response 구체적으로 명세하기

타운어스 백엔드 API에서는 별도로 정의된 error collection을 사용하고 있습니다. 400, 401, 403, 404, 409등의 error response에는 각각 에러케이스에 해당하는 code와 message가 포함됩니다.

이를 API 문서에 효과적으로 적용하기 위해 “@swagger_auto_schema”의 responses가 마크다운을 지원하는 점을 이용해 아래와 같이 사용했습니다.

각 error case를 ErrorCollection으로 정의
“swagger_auto_schema”의 responses에 error_collection 정리하기

위에서 사용한 error_collection은 해당 method에서 처리되는 에러케이스들입니다. API 문서에 함께 정리될 필요가 있어 위와 같이 각 status_code 별로 마크다운화 시켜 처리하였습니다. 그 결과는 아래와 같습니다.

위와 같이 에러케이스도 깔끔하고 편하게 정리가 됩니다. (세상 행복)

끝으로.

자주 바뀌면서 정말 빠른 속도로 진행되는 프로젝트에서 문서에 쏟을 시간이 없어 API 문서를 자동화 하게 되었고, 현재까지 잘 사용하고 있습니다. 직접 작성하고 있었으면 프로젝트 일정은 훨씬 늦어졌을 것이라 확신이 들 정도로 생산성에 큰 도움이 되었습니다 (사실 직접 작성한다고 해도 저거보다 잘 만들 자신이 없다…)

이제 “좋은" API 문서를 만들기 위해서 시간과 노력을 문서화 자체에 쏟는게 아닌 아름다운 코드를 쓰는데 쏟으면 됩니다.

DRF를 사용하신다면 Django REST Swagger나 Build-in API Documetation도 나쁘지 않지만 깔끔하고 구체적인 자동 문서화 툴인 drf-yasg도 사용해보시길 추천합니다.

--

--