API(三)之Requests and Responses
Request objects
REST框架引入了Request對象來
擴展常規的HttpRequest
,並提供更靈活的請求解析。Request
對象的核心功能是request.data
屬性,這與request.POST相似,但對
使用Web API更有用。
request.POST # Only handles form data. Only works for ‘POST‘ method. request.data # Handles arbitrary data. Works for ‘POST‘, ‘PUT‘ and ‘PATCH‘ methods.
Response objects
REST框架還引入了一個Response
對象,它是TemplateResponse的一種類型,它
使用未渲染的內容,並使用內容協商來確定正確的內容類型以返回給客戶端。
return Response(data) # Renders to content type as requested by the client.
Status codes
在您的視圖中使用數字HTTP狀態碼並不總是利於閱讀,如果您收到 an error code wrong你將很難註意到。 REST框架為每一個狀態碼更明確的標識符,如status
模塊中的HTTP_400_BAD_REQUEST。
使用這些標識符比使用數字標識符要好的多。
Wrapping API views
REST框架提供了兩個可用於編寫API視圖的wrappers。
- The
@api_view
裝飾器對function-based views有效。 - The
APIView
class對class-based views有效。
這些wrappers提供了一些功能,例如確保您在視圖中接收Request
實例,並將上下文添加到Response
對象,以便可以執行content negotiation。
The wrappers also provide behaviour such as returning 405 Method Not Allowed
responses when appropriate, and handling any ParseError
request.data
with malformed input.
Pulling it all together
好的,我們開始使用這些新的組件來寫幾個視圖。
views.py中
不再需要JSONResponse
class, 所以請刪除它。一旦完成這些,我們就可以開始重構我們視圖了.
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非常相似。我們還使用命名的狀態碼,這使得響應意義更加明顯。
以下是views.py
模塊中單個的代碼段視圖。
@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視圖並沒有什麽不同。
請註意,我們不再明確地將我們的請求或響應綁定到一個給定的內容類型。request.data
能夠處理輸入的 json
requests,但它也可以處理其他格式。同樣,我們使用數據返回響應對象,但允許REST框架將響應渲染成正確的內容類型。
Adding optional format suffixes to our URLs
我們的響應不再與單一內容類型連接,為了充分利用這個事實,我們可以為API端點添加一些格式後綴。使用格式後綴給urls明確指定一個格式,這意味著我們的API將能夠處理諸如http://example.com/api/items/4.json之類的urls。
首先在兩個視圖中添加一個format
關鍵字參數,就像這樣。
def snippet_list(request, format=None):
and
def snippet_detail(request, pk, format=None):
Now現在稍微更新urls.py
文件,另外給已經存在的urls附加一組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模式,但它給了我們一個簡單,幹凈的方式來引用特定的格式。
How‘s it looking?
從命令行開始測試API,就像我們在第1部分中所做的那樣。一切工作都非常相似,盡管如果發送無效請求,我們已經有了更好的錯誤處理。
我們可以像以前一樣獲取所有片段的列表。
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 header
來控制響應的格式:
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
或者通過附加格式後綴:
http http://127.0.0.1:8000/snippets.json # JSON suffix http http://127.0.0.1:8000/snippets.api # Browsable API suffix
Similarly,類似地,我們可以使用Content-Type header
來控制我們發送的請求的格式。
# 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" }
If you add a --debug
switch to the http
requests above, you will be able to see the request type in request headers.
如果您向上述的http requests添加--debug
,你將可以在請求頭中查看請求類型。
現在,在Web瀏覽器中打開API,訪問http://127.0.0.1:8000/snippets/。
API(三)之Requests and Responses