從本節我們開始真正接觸rest framework的核心部分。首先我們學習一下一些必備知識。
1. Request Object ——Request對象
rest framework 引入了一個繼承自HttpRequest
的Request
對象,該對象提供了對請求的更靈活解析。request
對象的核心部分是request.DATA
屬性,類似於request.POST
, 但在使用WEB API時,request.DATA
更有效。
request.POST # Only handles form data. Only works for ‘POST’ method.
request.DATA # Handles arbitrary data. Works any HTTP request with content.
2. Response Object ——Response對象
rest framework引入了一個Response
對象,它繼承自TemplateResponse
對象。它獲得未渲染的內容並通過內容協商content negotiation 來決定正確的content type返回給client。
return Response(data) # Renders to content type as requested by the client.
3. Status Codes
在views當中使用數字化的HTTP狀態碼,會使你的代碼不宜閱讀,且不容易發現代碼中的錯誤。rest framework爲每個狀態碼提供了更明確的標識。例如HTTP_400_BAD_REQUEST
在status
module。相比於使用數字,在整個views中使用這類標識符將更好。
4. 封裝API views
在編寫API views時,REST Framework提供了兩種wrappers:
@api_viwe
decorator for working with function based views.APIView
class for working with class based views.
這兩種封裝器提供了許多功能,例如,確保在view當中能夠接收到Request
實例;往Response
中增加內容以便內容協商content negotiation 機制能夠執行。
封裝器也提供一些行爲,例如在適當的時候返回405 Methord Not Allowed
響應;在訪問多類型的輸入request.DATA
時,處理任何的ParseError
異常。
5. 彙總
我們開始用這些新的組件來寫一些views。
我們不在需要JESONResponse
類(在前一篇中創建),將它刪除。刪除後我們開始稍微重構下我們的view
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)
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)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
上面的代碼是對我們之前代碼的改進。看上去更簡潔,也更類似於django的forms api形式。我們也採用了狀態碼,使返回值更加明確。
下面是對單個snippet操作的view更新:
@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)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
注意,我們並沒有明確的要求requests或者responses給出content type。request.DATA
可以處理輸入的json
請求,也可以輸入yaml
和其他格式。類似的在response返回數據時,REST Framework返回正確的content type給client。
6. 給URLs增加可選的格式後綴
利用在response時不需要指定content type這一事實,我們在API端增加格式的後綴。使用格式後綴,可以明確的指出使用某種格式,意味着我們的API可以處理類似http://example.com/api/items/4.json.的URL。
增加format
參數在views中,如:
def snippet_list(request, format=None):
and
def snippet_detail(request, pk, format=None):
現在稍微改動urls.py
文件,在現有的URLs中添加一個格式後綴pattterns (format_suffix_patterns
):
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = patterns('snippets.views',
url(r'^snippets/$', 'snippet_list'),
url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'),
)
urlpatterns = format_suffix_patterns(urlpatterns)
這些額外的url patterns並不是必須的。
7. How’s it looking?
繼續從命令行測試api,正如我們在教程第1部分中所做的那樣。所有的工作都非常類似,儘管我們在發送無效請求時有更好的錯誤處理。
我們可以像以前一樣得到所有片段的列表。
curl http://127.0.0.1:8000/snippets/
[{"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頭來控制返回的響應的格式:
curl http://127.0.0.1:8000/snippets/ -H 'Accept: application/json' # Request JSON
curl http://127.0.0.1:8000/snippets/ -H 'Accept: text/html' # Request HTML
或附加格式後綴:
curl http://127.0.0.1:8000/snippets/.json # JSON suffix
curl http://127.0.0.1:8000/snippets/.api # Browsable API suffix
類似地,我們可以使用內容類型頭控制發送的請求的格式
# POST using form data
curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
{"id": 3, "title": "", "code": "123", "linenos": false, "language": "python", "style": "friendly"}
# POST using JSON
curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
{"id": 4, "title": "", "code": "print 456", "linenos": true, "language": "python", "style": "friendly"}
Now go and open the API in a web browser, by visiting http://127.0.0.1:8000/snippets/.
8. 可瀏覽性
由於api基於客戶端請求選擇響應的內容類型,因此在web瀏覽器請求資源時,它將默認返回該資源的html格式表示。這允許api返回完全可web瀏覽的html表示。
擁有一個web可瀏覽的api是一個巨大的可用性勝利,它使開發和使用api變得更加容易。它還大大降低了其他想要檢查和使用您的api的開發人員進入的障礙。
有關可瀏覽API功能和如何自定義該功能的詳細信息,請參閱[可瀏覽API][可瀏覽API]主題。