[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):
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 스위치를 추가하면 요청 헤더에서 요청 유형을 볼 수 있습니다.
'Python > Django' 카테고리의 다른 글
[Django] RestfulFramework - Permission (0) | 2017.03.13 |
---|---|
[Django] RestFrameWork 튜토리얼 - 3. 클래스 base View (0) | 2017.03.10 |
[Django] RestFrameWork 튜토리얼 - 1. 직렬화 (0) | 2017.03.10 |
[Django] 템플릿 태그와 필터 (0) | 2017.03.08 |
[Django] 템플릿 (0) | 2017.03.08 |