포스트

Parsers

Parsers

1
2
3
웹 서비스와 상호작용 하는 기기는 데이터를 송신할 때 인코딩된 폼보다 좀 더 구조화된 포맷을 사용하는 경향이 있는데,
이는 단순한 폼보다 더 복잡한 데이터를 송신하기 때문이다.
- Malcom Tredinnick, Django developers group

REST framework는 다양한 미디어 타입을 가지는 요청을 허용하게 해주는 여러 빌트인 파서 클래스를 포함한다. 또한 커스텀 파서 정의를 지원해 API가 허용할 미디어 타입을 디자인할 수 있는 유연함을 제공한다.

How the parser is determined

뷰에 유효한 파서 설정은 항상 클래스 리스트로 정의된다. request.data에 접근하게 될 때, REST framework는 들어오는 요청의 Content-Type 헤더를 검사하고 요청 내용을 파싱하기 위해 어느 파서를 사용할지 결정한다.


Note
클라이언트 어플리케이션을 개발할 때 HTTP 요청에서 데이터를 송신하는 경우 Content-Type 헤더를 설정해야 한다.
만약 컨텐츠 유형을 설정하지 않는다면, 대부분의 클라이언트는 기본값으로 application/x-www-form-urlencoded를 사용한다.
예를 들어, jQuery의 .ajax() 메서드를 사용해 인코딩된 json 데이터를 송신할 때, contentType: 'application/json' 설정을 반드시 포함해야 한다.


Setting the parsers

파서의 기본값은 DEFAULT_PARSER_CLASSES 설정을 사용해 전역적으로 설정된다. 예를 들어, 다음의 설정은 기본값인 JSON 또는 폼 데이터가 아닌 JSON 컨텐츠를 가진 요청만 허용한다.

1
2
3
4
5
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
    ]
}

APIView 클래스 기반 뷰를 사용해 개별적인 뷰 또는 뷰셋을 위한 파서를 설정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    """
    JSON 컨텐츠를 가진 POST 요청을 허용하는 뷰
    """
    parser_classes = [JSONParser]

    def post(self, request, format=None):
        return Response({'received data': request.data})

또는 함수 기반 뷰에 @api_view 데코레이터를 사용할 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
from rest_framework.decorators import api_view
from rest_framework.decorators import parser_classes
from rest_framework.parsers import JSONParser

@api_view(['POST'])
@parser_classes([JSONParser])
def example_view(request, format=None):
    """
    JSON 컨텐츠를 가진 POST 요청을 허용하는 뷰
    """
    return Response({'received data': request.data})

API Reference

JSONParser

JSON 요청 컨텐츠를 파싱한다. request.data는 데이터 딕셔너리로 채워진다.

.media_type: application/json

FormParser

HTML 폼 컨텐츠를 파싱한다. request.data는 데이터의 QueryDict로 채워진다.

보통 HTML 폼 데이터를 온전히 지원하기 위해 FormParserMultiPartParser를 같이 사용한다.

.media_type: application/x-www-form-urlencoded

MultiPartParser

파일 업로드를 지원하는 multipart HTML 폼 컨텐츠를 파싱한다. 두 request.data 모두 QueryDict로 채워진다.

보통 HTML 폼 데이터를 온전히 지원하기 위해 FormParserMultiPartParser를 같이 사용한다.

.media_type: multipart/form-data

FileUploadParser

미가공 파일 업로드 컨텐츠를 파싱한다. request.data 속성은 업로드된 파일을 포함하는 하나의 키 file를 가지는 딕셔너리이다.

만약 FileUploadParser와 같이 사용되는 뷰가 filename URL 키워드 인자로 호출된다면 그 인자가 파일 이름으로 사용된다.

만약 filename URL 키워드 인자 없이 호출된다면, 클라이언트는 HTTP 헤더의 Content-Disposition 안에 파일 이름을 설정해야 한다. 예) Content-Disposition: attachment; filename=upload.jpg

.media_type: */*


Notes:

  • FileUploadParser는 파일을 미가공 데이터 요청으로 업로드할 수 있는 네이티브 클라이언트에서 사용하기 위한 것이다. 웹 기반 업로드 또는 multipart 업로드 지원이 가능한 네이티브 클라이언트에서는 MultiPartParser를 사용하는 것이 좋다.
  • 이 파서의 media_type은 어떤 컨텐츠 타입에도 매치가 되기 때문에 FileUploadParser는 하나의 API 뷰에서 사용되는 유일한 파서여야 한다.
  • FileUploadParser는 Django의 표준 FILE_UPLOAD_HANDLERS 설정과 request.upload_handlers 속성을 존중한다. 자세한 사항은 Django 문서에서 확인할 수 있다.

기본 사용 예시:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# views.py
class FileUploadView(views.APIView):
    parser_classes = [FileUploadParser]

    def put(self, request, filename, format=None):
        file_obj = request.data['file']
        # ...
        # do some stuff with uploaded file
        # ...
        return Response(status=204)

# urls.py
urlpatterns = [
    # ...
    re_path(r'^upload/(?P<filename>[^/]+)$^', FileUploadView.as_view()),
]

Custom parsers

사용자 정의 파서를 구현하려면 BaseParser를 재정의하고 .media_type 속성을 설정해야하며 .parse(self, stream, media_type, parser_context) 메서드를 구현해야 한다.

메서드는 request.data 속성을 채우기 위한 데이터를 반환해야 한다.

.parse()로 전달되는 인자는 다음과 같다.

Stream

요청의 바디를 나타내는 스트림과 유사한 객체

media_type

선택인자. 주어진다면 들어오는 요청 컨텐츠의 미디어 유형이 된다.

요청의 Content-Type: 헤더에 따라 정해지는데 렌더러의 media_type 속성보다 더 구체적일 수 있으며 미디어 유형 인자를 포함할 수 있다. 예를 들면 "text/plain; charset=utf-8".

parser_context

선택인자. 주어진다면 요청 컨텐츠를 파싱하는데 요구되는 추가적인 컨텍스트를 포함하는 딕셔너리가 된다.

기본값으로 다름의 키를 포함한다: view, request, args, kwargs

Example

다음은 요청의 바디를 나타내는 문자열로 request.data 속성을 채우는 플레인 텍스트 파서의 예시이다.

1
2
3
4
5
6
7
8
9
10
11
class PlainTextParser(BaseParser):
    """
    플레인 텍스트 파서
    """
    media_type = 'text/plain'

    def parse(self, stream, media_type=None, parser_context=None):
        """
        단순히 요청의 바디를 표현하는 문자열을 반환한다.
        """
        return stream.read()

Thrid party packages

다음의 서드파티 패키지 또한 사용할 수 있다.

YAML

REST framework YAMLYAML 파싱과 렌더링 지원을 제공한다. 이전에는 REST framework 패키지에 직접 포함되어 있었지만 지금은 서드파티 패키지로 지원된다.

Installation & configuration

pip을 이용해 설치한다.

1
$ pip install djangorestframework-yaml

REST framework 설정을 변경한다.

1
2
3
4
5
6
7
8
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_yaml.parsers.YAMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_yaml.renderers.YAMLRenderer',
    ],
}

XML

REST Framework XML은 간단한 약식 XML 포맷을 제공한다. 이전에는 REST framework에 직접 포함되어 있었으나 지금은 서드파티 패키지로 지원된다.

Installation & configuration

pip을 이용해 설치한다.

1
$ pip install djangorestframework-xml

REST framework 설정을 변경한다.

1
2
3
4
5
6
7
8
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_xml.parsers.XMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_xml.renderers.XMLRenderer',
    ],
}

MessagePack

MessagePack은 빠르고 효율적인 이진 직렬화 포맷이다. Juan Riaza가 REST framework에 MessagePack 렌더러와 파서 지원을 제공하는 djangorestframework-msgpack 패키지를 관리한다.

CamelCase JSON

djangorestframework-camel-case는 REST framework를 위한 카멜케이스 JSON 렌더러와 파서를 제공한다. 이는 시리얼라이저가 파이썬식 필드 명을 사용하게 하지만 API에서는 자바스크립트식 카멜 케이스 필드 명으로 보이게 한다. Vitaly Babiy가 관리한다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.