ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Django REST Framework API 문서 자동화 하기(feat.drf-yasg)
    💻 프로그래밍/Django 2018. 12. 31. 19:10

    안녕하세요! Jay입니다:D 이번 포스팅은 DRF(Django REST Framework) API 문서를 만들어 보겠습니다.

    물론 자동 으로요!! 사실 이번 포스팅은 회사에서 API문서를 수정하거나, 다른 웹페이지로 이동시키는 문제때문에 이것 저것 찾아 보다가 찾아낸 방법입니다. API 한두개야 그냥 직접 타이핑 할 수 있지만, 아주 방대한 API의 경우 매번 새로 타이핑하는건...정말 노가다죠 ㅎㅎ

    아주 친절하게도 우리에게는 오픈소스라는 희망이 있었고, 다양한 DRF API 문서 자동화 패키지들이 존재했습니다. 

    예를들어 Django REST Swagger, Apiary, RAML 등이 있는데, 이번 포스팅에서 사용할 패키지는

    drf-yasg 입니다.

    참고자료 : https://drf-yasg.readthedocs.io/en/stable/#

    아 그리고, 이번 포스팅은 http://jay-ji.tistory.com/30 (Django REST Framework 사용방법)에서 사용한 프로젝트를 기반으로 진행되니 혹시 DRF에 대해 궁금하신분은 이전 포스팅을 확인해주세요!:D

    자 이제 시작 해보겠습니다.

    ※ 패키지 설치

     $ pip install -U drf-yasg

    패키지를 설치했으면 setting.py의 INSTALLED_APPS에 추가해줍니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Application definition
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'movie',
        'rest_framework',
        'drf_yasg',
    ]
     


    다음으로 urls.py에 아래와 같이 추가해 주시면 됩니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    # Django REST Framework API Auto create
    from django.conf.urls import url
    from drf_yasg.views import get_schema_view
    from rest_framework.permissions import AllowAny
    from drf_yasg import openapi
     
    schema_url_v1_patterns = [
        url(r'^v1/', include('movie.urls', namespace='movie_api')),
    ]
     
    schema_view_v1 = get_schema_view(
        openapi.Info(
            title="Jay Open API",
            default_version='v1',
            description="안녕하세요. Jay의 Open API 문서 페이지 입니다.",
            terms_of_service="https://www.google.com/policies/terms/",
            contact=openapi.Contact(email="Jay@google.com"),
            license=openapi.License(name="Jay's CodeFactory"),
        ),
        validators=['flex'], #'ssv'],
        public=True,
        permission_classes=(AllowAny,),
        patterns=schema_url_v1_patterns,
    )
     
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^v1/', include('movie.urls', namespace='movie_api')),
     
        # Auto DRF API docs
        url(r'^swagger(?P<format>\.json|\.yaml)/v1$', schema_view_v1.without_ui(cache_timeout=0), name='schema-json'),
        url(r'^swagger/v1/$', schema_view_v1.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
        url(r'^redoc/v1/$', schema_view_v1.with_ui('redoc', cache_timeout=0), name='schema-redoc-v1'),
    ]

    c

    서버를 실행하기 전에  $ pip install flex 를 해줍니다.

    flex는 JSON schema를 체크하는 검사기 패키지 입니다. 

    JSON Schema 에 대한 내용은 http://tcpschool.com/json/json_schema_schema 여기를 참고하시길 바랍니다.

    참고로 openapi.Info 에 validators 설정에 보면 공식문서에는 flex, ssv 두개를 쓰는데, 

    저같은 경우는 ssv 패키지를 설치해도 에러가 나더라고요 ㅎㅎ 그래서 flex 하나만 사용하였습니다.(이것때매 삽질많이 했네요 ㅎㅎ)

    URL 패턴에 저장한 이 URL들은 drf-yasg에서 지원하는 API문서 자동화 UI(?)들 입니다. drf-yasg 는redoc.ui 와 swagger.ui를 지원하는데요, 이렇게 쓰면 해당 URL로 접속해 원하는 UI를 사용할 수 있습니다.


    ※ 접속해보기

    이제 127.0.0.1:8000/redoc/v1/ 로 접속해 보도록 하겠습니다.

    그럼 이런 화면이 나옵니다. 이전 강의에서 만들어 놓은 API들이 자동으로 어떤 응답에 어떤 형태인지 자동으로 만들어졌습니다.

    list, create, read는 get, post 등을 인식해서 자동으로 만들어주는 타이틀입니다. 

    이제 이 타이틀과 API설명들은 커스터마이징 해보겠습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    # -*- coding: utf-8 -*-
    from .models import Movie
    from django.http import Http404
    from rest_framework import status
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from django.http import JsonResponse
    from .serializers import MovieSerializer
     
    class MovieList(APIView):
        """
            영화리스트를 저장하거나 불러오는 API
            ---
            # 내용
                - title : 영화제목
                - year : 영화 출시 년도
                - genre : 영화 장르
        """
        @classmethod
        def get_extra_actions(self):
            return []
     
        def post(self, request, format=None):
            serializer = MovieSerializer(data=request.data)
            if serializer.is_valid() :
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
     
     
        def get(self, request, format=None):
            queryset = Movie.objects.all()
            serializer = MovieSerializer(queryset, many=True)
            return Response(serializer.data)
     
     
    class MovieDetail(APIView) :
        """
            영화리스트에서 특정 id를 가지는 데이터를 가져오는 API
            ---
            # 내용
                - title : 영화제목
                - year : 영화 출시 년도
                - genre : 영화 장르
        """
        def get_object(self, pk):
     
            try:
                return Movie.objects.get(pk=pk)
            except Movie.DoesNotExist :
                raise Http404
     
        def get(self, request, pk):
            movie = self.get_object(pk)
            serializer = MovieSerializer(movie)
            return Response(serializer.data)
     
        def put(self, request, pk, format=None):
            movie = self.get_object(pk)
            serializer = MovieSerializer(movie, data=request.data)
            if serializer.is_valid() :
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
     
        def delete(self, request, pk, format=None):
            movie = self.get_object(pk)
            movie.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)


    위 사진처럼 입력한 내용들이 적용하여 나옵니다.

    주의할 점은 아래 사진에서 보이는 타이틀을 쓰고 엔터를 한다음 ---를 써줘야 타이틀이 제대로 커스터마이징 됩니다.

    다음은  127.0.0.1:8000/swagger/v1/ 로 접속해 보도록 하겠습니다.

    redoc UI이와는 또다른 UI인 swagger UI입니다. swagger UI의 장점은 아래와 같이 Postman의 기능을 사용할 수 있다는 점입니다.

    Try it out 버튼을 클릭하고  Execute 버튼을 클릭하면, 다음과 같이 Postman에서 api가 호출되는 것 처럼 똑같이 확인할 수 있습니다.

    지금까지 DRF API문서를 자동화 하는 drf-yasg 패키지를 사용해 보았습니다. 여기서 다룬 내용 뿐만이 아니라 조금더 디테일한 내용들이 있는데, 아직 저도 못해봤네요 ㅎㅎ

    참고블로그 : https://medium.com/towncompany-engineering/%EC%B9%9C%EC%A0%88%ED%95%98%EA%B2%8C-django-rest-framework-api-%EB%AC%B8%EC%84%9C-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0-drf-yasg-c835269714fc

    저는 이분의 블로그를 참고했습니다. 저보다 더 디테일하게 설명을 해놓으셨고, 저는 이번포스팅에서 제가 직접하면서 에러났던 부분이나 해맸던 부분을 추가로 작성하였습니다 ㅎㅎ 이상으로 오늘의 포스팅을 마치겠습니다.

    이세상 모든 코린이들이 고수가 되는 그날까지~~즐거운 코딩하세요~ 아디오스:D 

    댓글

운동하는 개발자 JAY-JI