Django REST Framework/DRF 일반

[DRF] 공식 문서 - Content negotiation 정리

bluebamus 2024. 1. 22.

 1. 콘텐츠 협상(Content negotiation)

   - 컨텐츠 협상은 클라이언트 또는 서버의 선호도에 따라 클라이언트에게 반환할 수 있는 여러 표현 중 하나를 선택하는 과정이다.

 

   1) 허용되는 렌더러 결정(Determining the accepted renderer)

      - REST 프레임워크는 간단한 스타일의 컨텐츠 협상을 사용하여 사용 가능한 렌더러, 각 렌더러의 우선순위 및 클라이언트의 "Accept:" 헤더를 기반으로 클라이언트에게 반환할 미디어 유형을 결정한다. 이 사용되는 스타일은 부분적으로 클라이언트 주도적이며, 부분적으로 서버 주도적이다.
         - 더 구체적인 미디어 타입은 덜 구체적인 미디어 타입보다 우선시된다.
         - 여러 미디어 타입이 동일한 구체성을 가지는 경우, 주어진 뷰에 구성된 렌더러의 순서에 따라 우선순위가 결정된다.

 

      - 예를 들어, 다음과 같은 Accept 헤더가 주어진 경우:

application/json; indent=4, application/json, application/yaml, text/html, */*

 

      - 각각의 미디어 타입에 대한 우선순위는 다음과 같다:
         - application/json; indent=4
         - application/json, application/yaml, text/html
         - */ *


      - 만약 요청된 뷰가 YAML과 HTML을 위한 렌더러만 구성되어 있다면, REST 프레임워크는 renderer_classes 목록이나 DEFAULT_RENDERER_CLASSES 설정에 나열된 첫 번째 렌더러를 선택한다.

      - HTTP Accept 헤더에 대한 자세한 내용은 RFC 2616을 참조하면 된다.

         - RFC 2616 : https://www.rfc-editor.org/rfc/rfc9110.html

 


 

      - 참고: "q" 값은 REST 프레임워크가 선호도를 결정할 때 고려되지 않는다. "q" 값의 사용은 캐싱에 부정적인 영향을 미치며, 작성자의 의견으로는 콘텐츠 협상에 불필요하고 복잡한 접근법이다.

      - HTTP 사양은 서버 기반 선호도를 클라이언트 기반 선호도에 대해 어떻게 가중시켜야 하는지를 일부러 명시하지 않았으므로 이는 유효한 접근 방식이다.


 

 2. 사용자 정의 콘텐츠 협상(Custom content negotiation)

   - REST 프레임워크에서 사용자 정의 콘텐츠 협상 체계(custom content negotiation scheme)를 제공하는 경우는 드물다. 그러나 필요한 경우 이를 수행할 수 있다. 사용자 정의 콘텐츠 협상 체계를 구현하려면 BaseContentNegotiation을 재정의하면 된다.

   - REST 프레임워크의 콘텐츠 협상 클래스는 요청에 대한 적절한 파서와 응답에 적합한 렌더러의 선택을 처리하므로, .select_parser(request, parsers) 및 .select_renderer(request, renderers, format_suffix) 메서드를 모두 구현해야 한다.

   - select_parser() 메서드는 사용 가능한 파서 목록 중 하나의 파서 인스턴스를 반환하거나, 요청을 처리할 수 있는 파서가 없는 경우 None을 반환해야 한다.

   - select_renderer() 메서드는 (렌더러 인스턴스, 미디어 타입)으로 이루어진 튜플을 반환하거나 NotAcceptable 예외를 발생시켜야 한다.

 

   1) Example

      - 다음은 클라이언트 요청을 무시하고 적절한 파서 또는 렌더러를 선택할 때 사용되는 사용자 정의 콘텐츠 협상 클래스이다.

from rest_framework.negotiation import BaseContentNegotiation

class IgnoreClientContentNegotiation(BaseContentNegotiation):
    def select_parser(self, request, parsers):
        """
        Select the first parser in the `.parser_classes` list.
        """
        return parsers[0]

    def select_renderer(self, request, renderers, format_suffix):
        """
        Select the first renderer in the `.renderer_classes` list.
        """
        return (renderers[0], renderers[0].media_type)

 

   2) 콘텐츠 협상 설정(Setting the content negotiation)

      - 기본 콘텐츠 협상 클래스는 DEFAULT_CONTENT_NEGOTIATION_CLASS 설정을 사용하여 전역적으로 설정할 수 있다. 예를 들어, 다음과 같은 설정은 우리의 예시인 IgnoreClientContentNegotiation 클래스를 사용할 것이다.

REST_FRAMEWORK = {
    'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'myapp.negotiation.IgnoreClientContentNegotiation',
}

 

      - 또한 APIView 클래스 기반 뷰를 사용하여 개별 뷰 또는 뷰셋에 대해 사용할 콘텐츠 협상을 설정할 수도 있다.

from myapp.negotiation import IgnoreClientContentNegotiation
from rest_framework.response import Response
from rest_framework.views import APIView

class NoNegotiationView(APIView):
    """
    An example view that does not perform content negotiation.
    """
    content_negotiation_class = IgnoreClientContentNegotiation

    def get(self, request, format=None):
        return Response({
            'accepted media type': request.accepted_renderer.media_type
        })

 

 - 공식 사이트 문서 : https://www.django-rest-framework.org/api-guide/content-negotiation/

 

Content negotiation - Django REST framework

 

www.django-rest-framework.org

 

댓글