[Django] DRF 에서 APIView 를 왜 사용하는 것인가?

msung99·2023년 10월 9일
0
post-thumbnail

학습배경

Django 로 개발을 하다보면 APIView 의 개념에 대해선 빼놓을 수 없을 것이고, 지금껏 저도 개발을 해오면서 정작 APIVIEW 에 대한 이론을 제대로 학습한 경험이 없습니다. 이번 기회에 핵심적인 부분들만 간단히 요약하여 정리해보고, 추후 포스트들에서 많은 개념들을 천천히 추가해보고자 합니다.


APIView 란?

[Django] 클레스 기반 뷰(CBV) 와 함수 기반 뷰(FBV) 의 차이점은 무엇이고, 언제 사용하는게 좋을까? 에서도 다루었듯이, 장고로 개발할 수 있는 전형적인 구조는 2가지가 있습니다. 이 중에서 APIView 를 활용하는 방법이 바로 CBV 의 대표적인 구현 방식입니다.

CBV

그렇다면 클래스형 뷰의 특징은 뭐였는지 다시 상기해보면, 공통적인 함수들의 재사용이 가능하다는 특징이 있었습니다. 또한 이를 통해 같은 코드를 재사용해서는 안된다는 DRY 정책에 알맞게 코드를 작성하기도 쉬워집니다.

사용 코드

class MyPost(APIView):
  def get(self, request, format=None):
    post = Post.objects.all()
    serializer = PostSerializer(post, many = true)
    return Response(serializer.done)
    
  def post(self, requuest, format=None)
    serializer = PostSerializer(data=request.data)
    if serializer.is_valid():
      serializer.save()
      return Response(seializaer.data)
    return Response(serializer.errors)

이는 함수형 뷰 @api_view 를 통해 HTTP 메소드를 지정해준 것 처럼, 동일한 이름의 내부 메소드를 정의해주면 됩니다. 덕분에 코드 흐름도 이해하기가 쉬워집니다.


사용 방식

지금부터 APIView 를 사용하기 위한 최소한의 핵심 동작원리만을 언급하겠습니다.

as_view()

APIView를 url과 연결하기 위해서는 url_patterns 에 APIVIew.as_view()를 명시해야 합니다.

path("/hello", my.as_view(), name="user_detail")

dispatch()

이때 APIView 클래스의 disptach() 함수의 코드를 살펴봅시다.

def dispatch(self, request, *args, **kwargs):
    """
    `.dispatch()` is pretty much the same as Django's regular dispatch,
    but with extra hooks for startup, finalize, and exception handling.
    """
    self.args = args
    self.kwargs = kwargs
    request = self.initialize_request(request, *args, **kwargs) # 요청 정보 초기화 및 converting
    self.request = request
    self.headers = self.default_response_headers 

    try:
        self.initial(request, *args, **kwargs)

        # 적절한 핸들러 메소드 위임
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(),
                              self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed

        response = handler(request, *args, **kwargs)

    except Exception as exc:
        response = self.handle_exception(exc) # 에러 핸들링

    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

dispatch 함수는 django 프레임워크의 class based view의 dispatch와 비슷하지만, 예외 처리나 초기 permission check와 같은 훅을 제공합니다.

동작원리

실행 흐름을 큰 틀에서 정리하면 다음과 같습니다.

  • 1) wsgi에서 온 요청을 drf에서 사용하는 요청으로 변환한다.
  • 2) 요청을 핸들러에게 위임하기 전 permission, throttling 등의 처리를 수행한다.
  • 3) request method를 확인하고 APIView에 request method에 해당하는 이름의 handler가 있는지 검증한다.
  • 4) 실제 요청을 위임한다.
  • 4-a) 요청 중 발생한 에러가 있다면 잡아서 핸들링한다.
  • 5) 응답을 변환하는 작업을 수행후 반환한다.

정리

정리를 해보자면, APIView 는 클래스 기반의 CBV(class base view) 의 개발 방식이며, 반대로 @api_view 는 함수기반의 FBV(function base view) 방식입니다.

APIView 는 렬화, 인증, 사용량 제한, 권한 등 여러가지 기본 설정을 제공합니다. 이러한 CBV 형태로 작성시, http 메소드에 해당하는 함수를 만들어줘야 합니다. 해당 함수 명은 지정되어 있으며, http의 메소드 명과 동일합니다. (함수명이 틀릴 경우 해당 메소드는 사용할수 없는 메소드로 간주 합니다. )

url에는 파라미터인자를 선언하므로 인자 pk를 받아야 하는 get/put/delete가 하나의 클래스, 파라미터가 필요 없는 gets/post가 하나의 클래스로 만든후 각각의 url로 선언 해야 합니다.


참고

profile
블로그 이전했습니다 🙂 : https://haon.blog

0개의 댓글