1. 程式人生 > >API(三)之Requests and Responses

API(三)之Requests and Responses

link col 需要 有用 highlight note -a 存在 pattern

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。

  1. The @api_view 裝飾器對function-based views有效。
  2. 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

exception that occurs when accessing 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