2021年7月24日土曜日

【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス

【和訳】Django Rest Framework クイックスタート

【和訳】Django Rest Framework チュートリアル1:シリアル化

【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス

【和訳】Django Rest Framework チュートリアル3:クラスベースのビュー

【和訳】Django Rest Framework チュートリアル4:認証とアクセス許可

【和訳】Django Rest Framework チュートリアル5:リレーションとハイパーリンクされたAPI

【和訳】Django Rest Framework チュートリアル6:ビューセットとルーター 


チュートリアル2:リクエストとレスポンス

これから、RESTフレームワークのコアについて実際に説明していきます。
いくつかの重要な構成要素を紹介しましょう。


リクエストオブジェクト

RESTフレームワークRequestは、通常のHttpRequestを拡張するオブジェクトを導入し、より柔軟なリクエスト解析を提供します。

Requestオブジェクトのコア機能はrequest.data属性です。
これは
request.POSTに似ていますが、WebAPIの操作に役立ちます。

request.POST  # フォームデータしか処理しない。 POSTメソッドの時のみ処理する。
request.data  # 任意のデータを処理する。 POSTやPUTやPATCHメソッドでも処理する。


レスポンスオブジェクト

RESTフレームワークはResponseオブジェクトを採用している、これは、TemplateResponseの一種であり、レンダリングされていないコンテンツを取得し、コンテンツネゴシエーションを使用して、クライアントに返す正しいコンテントタイプを決定する。

return Response(data)  # クライアントから要求されたコンテントタイプにレンダリングする


ステータスコード

ビューでHTTPステータスコードを数値として扱っても、その意味が、必ずしも明確に読み取れるとは限りません。
エラーコードを間違えた場合には、気付かないことが多々あります。
RESTフレームワークは
statusモジュール中にHTTP_400_BAD_REQUESTなど、各ステータスコードに対してより明確な識別子を提供ます。
数値識別子を使用するのではなく、全体を通して、これらを使用することをお勧めします。


APIビューのラッピング

RESTフレームワークは、APIビューの記述に使用できる2つのラッパーを提供します。

  1. @api_view:関数ベースのビューを操作するためデコレータ。
  2. APIView:クラスベースのビューを操作するためクラス。

これらのラッパーは、ビューでRequestインスタンスを確実に受信するようにしたり、コンテンツネゴシエーションを実行できるようResponseオブジェクトにコンテキストを追加したりするなど、いくつかの機能を提供します

これらのラッパーは、適切な場合405 Method Not Allowedレスポンスを返したり、不正な形式の入力を含むrequest.dataにアクセスする際に発生するParseError例外を処理する動作も提供します。


れらをすべてまとめる

では、これらの新しいコンポーネントを使用して、ビューを少しリファクタリングしてみましょう。

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):
    """
    全コードスニペットを一覧表示、スニペットを新規作成する
    """
    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)

インスタンスビューは、前の例を改善したものです。
少し簡潔になり、FormsAPIを使用していた場合と非常によく似たコードになりました。
また、名前付きステータスコードを使用しているため、レスポンスの意味がより明確になります。

次は、views.pyモジュール内の個々のスニペットのビューです。

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    コードスニペットを個別表示・更新・削除する
    """
    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リクエストを処理できますが、他の形式でも処理できます。
同様に、データの入ったレスポンスオブジェクトを返しますが、レスポンスに正しいコンテンツタイプを持たせるよう、
RESTフレームワークにレンダリングさせる必要があります。


URLに対して、フォーマットタイプの接尾語をオプションとして付け加える

レスポンスが単一のコンテンツタイプに固定する必要がないことを利用するために、APIエンドポイントにフォーマットタイプの接尾語を追加しましょう。フォーマットタイプの接尾語を使用すると、特定のフォーマットを明示的に参照するURLが得られます。これは、APIがhttp://example.com/api/items/4.jsonなどのURLを処理できることを意味します

さっきの2つのビューにformatキーワード引数を追加するところから見ていきましょう。

def snippet_list(request, format=None):

そして

def snippet_detail(request, pk, format=None):

次に、既存のURLに加え、一連のformat_suffix_patternsを追加するために、snippets/urls.pyファイルを少し更新しましょう。

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    path('snippets/', views.snippet_list),
    path('snippets/<int:pk>', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

必ずしもこれらの追加のURLパターンを追加する必要はありませんが、特定の形式を参照するためのシンプルでクリーンな方法を提供します。


どういう風になる?

チュートリアルパート1で行ったように、コマンドラインからAPIをテストしましょう
さきほどとほぼ同様に動作します。
無効なリクエストを送信すると、多少マシなエラー処理がされます。

以前と同様に、すべてのスニペットのリストを取得できます。

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  # JSONをリクエストする
http http://127.0.0.1:8000/snippets/ Accept:text/html         # HTMLをリクエストする

あるいは、フォーマット接尾語を追加しても制御できます:

http http://127.0.0.1:8000/snippets.json  # 接尾語にjsonを加える
http http://127.0.0.1:8000/snippets.api   # 接尾語にapiを加える

同様に、Content-Typeヘッダーを使用して、送信するリクエストの形式を制御できます

# formデータをPOSTする
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"
}

# JSONデータをPOSTする
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スイッチを追加すると、リクエストヘッダー中のリクエストタイプを表示できます。

次に、http://127.0.0.1:8000/snippets/にWebブラウザでアクセスし、APIを開きます。


ブラウザからの閲覧性

APIはクライアントの要求に基づいてレスポンスのコンテンツタイプを選択するため、デフォルトでは、リソースがWebブラウザーによって要求されると、リソースのHTML形式表示が返されます。
これにより、APIは完全にWebブラウザで閲覧可能なHTML表示を返すことができます。

Webブラウザで閲覧可能なAPIが使えると、ユーザビリティが大幅に向上し、APIの開発と使用がはるかに簡単になります。
また、あなたが作成したAPIを調査して操作したい他の開発者にとって、参入障壁が劇的に低くなります。

ブラウザから閲覧可能なAPI機能とそのカスタマイズ方法の詳細については、ブラウザから閲覧可能なAPIトピックを参照してください


次は?

チュートリアルパート3では、クラスベースのビューを使うことから始め、汎用ビュー(generic view)により、私たちが書く必要のあるコード量をどれほど減らせるかを見ていきましょう。

0 件のコメント:

コメントを投稿

【和訳】Django Rest Framework 目次

目次 【和訳】Django Rest Framework クイックスタート 【和訳】Django Rest Framework チュートリアル1:シリアル化 【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス 【和訳】Django Res...