[Request 객체]


REST FRAMEWORK는 일반 HttpRequest 를 확장하고 Request Parsing에 있어서 좀더 유연한 방법을 제공합니다.


Request 객체의 핵심기능은 request.data 속성입니다. 이것은 request.POST와 유사합니다. 그러나 WEB API에 있어서 훨씬더 유용합니다.


request.POST  # 오직 form Data만 핸들링가능. 오직 POST방식만 동작.
request.data  # 속성 데이터를 핸들링.  POST, PUT, PATCH 방식에 동작.

[Response 객체]


REST FRAMWORK는 또한 Response 객체도 도입했는데 이것은 TemplateResponse 타입으로 랜더링 되지 않은 콘텐츠를 사용하고 콘텐츠를 올바르게 가공하여 클라이언트에게 올바른 콘텐츠를 반환 할 수 있도록 합니다.



return Response(data)  # 클라이언트가 요청한 타입으로 컨텐츠를 리턴합니다.

[상태코드]


View에서 HTTP 상태 코드를 사용한다고 해서 분명하게 확인 할 수 있는 것은 아니며, 오류 코드를 통지하는 것이 쉽지는 않습니다. REST FRAMEWORK는 각 상태코드에 대해서 보다 명확히 식별자를 제공합니다. 예를들면 status 모듈 안의  HTTP_400_BAD_REQUEST 입니다. 숫자 식별자를 사용하는 것 보다 전체적으로 이러한 방식을 사용하는것이 훨씬 효과적입니다.


[ API views ]


REST FRAMEWORK는 API 보기를 작성하는데 사용할 수 있는 2개의 Wrapper 를제공합니다.

1. 함수 기반 View 작업을 위한 @api_view 데코레이터

2. 클래스 기반 View 작업을 위한 APIView 클래스


이러한 Wrapper는 Reqest 인스턴스를 전달 받는지 확인하는 것과 같은 몇가지 기능을 제공합니다. 그리고 Content를 가공 할 수 있도록 컨텍스트를 Response객체에 추가합니다.


해당 랩퍼는 405 Methond Not Allowed 와 같은 허용하지 않는 응답을 리턴하는 것과 같은 동작도 제공합니다.


request.data에 엑세스 할떄 발생하는 모든 ParseError 예외를 처리할 수도 있습니다.


[실전]


이제 위의 구성요소들을 사용해서 몇가지 예를 작성해보겠습니다.


첫번째 포스팅에서 사용했던 예제를 사용하겠습니다.


기존의 snippets/view.py를 열고 내용을 아래로 대체합니다.


from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    List all snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = SnippetSerializer(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)

방금 삭제한 소스코드 보다 지금의 예제는 훨씬더 세련되어져 있습니다. 코드가 좀더 간결해지고, Forms API를 사용하는 경우와 매우 비슷합니다. 또한 응답의 의미를 분명하게 해주는 상태코드를 사용하고 있습니다.


list를 작성했으니 detail을 작성해볼게요.


@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a snippet instance.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

위의 예제들은 일반적으로 Django View의 작업과 크게 다르지 않다는 것을 알수 있습니다.

더이상 특정 콘텐츠에 대한 타입에 대한 요청이나 응답을 명시적으로 묶어두지 않습니다.

request.data는 들어오는 json 요청을 처리할 수 있지만, 다른 형식도 처리할 수 있습니다.

마찬가지로 data로 응답 객체를 반환하지만, REST FRAMEWORK가 Response를 올바른 콘텐츠로 랜더링 하도록 허용합니다.


[ URL에 접미사 추가하기 ]


어떤 방식인지 한마디로 설명하자면 http://example.com/api/items/4.json.과 같이 처리 할수 있다는 말입니다.


list와 detail 2가지 view 모두에 format 키워드 인수를 추가하는것으로 시작합니다.


def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
이제 urls.py 파일을 약간 손보기로 하겠습니다. format_suffix_patterns 를 추가해줍니다.


from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

이러한 추가 URL 패턴을 반드시 추가 할필요는 없지만, 특정 형식을 간단하고 명확하게 참조 할 수 있도록 합니다.


[결과를 봅시다]


첫번쨰 포스트에서 테스트했던것 처럼 테스트해보세요. 첫번째 포스트와 비슷하게 작동할 겁니다. 유효하지 않은 request 에 대해서 훨씬 nice하게 error을 핸들링 할 수 있습니다.


http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "id": 1,
    "title": "",
    "code": "foo = \"bar\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  },
  {
    "id": 2,
    "title": "",
    "code": "print \"hello, world\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  }
]

Accept 헤더를 사용해서 응답의 형식을 제어할수도 있죠


http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML

또는 format 접미사를 추가해도 됩니다.


http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

마찬가지로 Content-Type 헤더를 사용해서 보내는 요청의 형식을 제어할수 있습니다.


# POST using form data
http --form POST http://127.0.0.1:8000/snippets/ code="print 123"

{
  "id": 3,
  "title": "",
  "code": "print 123",
  "linenos": false,
  "language": "python",
  "style": "friendly"
}

# POST using JSON
http --json POST http://127.0.0.1:8000/snippets/ code="print 456"

{
    "id": 4,
    "title": "",
    "code": "print 456",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

위의 http 요청에 --debug 스위치를 추가하면 요청 헤더에서 요청 유형을 볼 수 있습니다.



Posted by C마노
,