2021年7月25日日曜日

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

【和訳】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:ビューセットとルーター 


チュートリアル5:リレーションとハイパーリンクされたAPI

現在、API内のリレーションは、主キーを使用して表されています。
チュートリアルのこのページでは、リレーションを表すために、主キーの代わりにハイパーリンクを使用することで、APIの凝集度と発見可能性を向上させます。


APIのルートのエンドポイントを作成する

現在、「スニペット」と「ユーザー」のエンドポイントがありますが、APIへの単一のエントリポイントはありません。
これを作成するには、通常の関数ベースのビューと、前
に紹介し@api_viewデコレータを使用しますsnippets/views.pyに追加します:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse


@api_view(['GET'])
def api_root(request, format=None):
    return Response({
        'users': reverse('user-list', request=request, format=format),
        'snippets': reverse('snippet-list', request=request, format=format)
    })

ここで2つのことに注意する必要があります。
まず、
完全修飾URLを返すためにRESTフレームワークのreverse関数を使用しています。
次に、URLパターンは、後で
snippets/urls.py内で宣言する便利な名前で識別されます。


ハイライトされたスニペットのエンドポイントを作成する

明らかにコードスニペットAPIに欠けている他の機能は、エンドポイントを強調表示するコードです。

他のすべてのAPIエンドポイントとは異なり、JSONは使用せず、代わりにHTML表現を使用したいです。
RESTフレームワークによって提供されるHTMLレンダラーには2つのスタイルがあります。
1つはテンプレートを使用してレンダリングされたHTMLを処理するためのもので、
もう1つは事前にレンダリングされたHTMLを処理するためのものです。
2番目のレンダラーは、今回、エンドポイントに使用したいレンダラーです。

コードハイライトビューを作成するときに考慮する必要があるもう1つのことは、使用できる既存の具体的な汎用ビューがないことです。
オブジェクトインスタンスではなく、オブジェクトインスタンスのプロパティを返したいのです。

具体的なジェネリックビューを使用する代わりに、インスタンスを表すために基底クラスを使用し、独自の.get()メソッドを作成しますsnippets/views.pyに追加します:

from rest_framework import renderers
from rest_framework.response import Response

class SnippetHighlight(generics.GenericAPIView):
    queryset = Snippet.objects.all()
    renderer_classes = [renderers.StaticHTMLRenderer]

    def get(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

いつものように、作成した新しいビューをURLconfに追加する必要があります。snippets/urls.py中の新しいAPIルートに、新しいURLパターンを追加します

path('', views.api_root),

次に、スニペットのハイライトのURLパターンを追加します。

path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view()),


APIのハイパーリンク

エンティティ間のリレーションを処理することは、WebAPI設計のより困難な側面の1つです。
リレーションを表すために選択できる方法はたくさんあります。

  • 主キーの使用。
  • エンティティ間のハイパーリンクの使用。
  • 関連するエンティティで一意の識別スラッグフィールドを使用します。
  • 関連するエンティティのデフォルトの文字列表現を使用します。
  • 親表現内に関連エンティティをネストします。
  • 他のカスタム表現

RESTフレームワークは、これらすべてのスタイルをサポートし、順方向または逆方向のリレーション全体に適用したり、汎用外部キーなどのカスタムマネージャー全体に適用したりできます。

ここでは、エンティティ間でハイパーリンクスタイルを使用します。そのために既存のModelSerializerの代わりHyperlinkedModelSerializerを用いて、シリアライザーを拡張するように変更します

HyperlinkedModelSerializerは、ModelSerializerとは以下の点で異なります

  • デフォルトでは、idフィールドは含まれていません
  • HyperlinkedIdentityFieldを使用して、urlフィールドが含まれます
  • リレーションシップはPrimaryKeyRelatedFieldの代わりに、HyperlinkedRelatedField使用します

ハイパーリンクを使用するように、既存のシリアライザーを簡単に書き直すことができます。
snippets/serializers.pyに以下を追加します:

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')

    class Meta:
        model = Snippet
        fields = ['url', 'id', 'highlight', 'owner',
                  'title', 'code', 'linenos', 'language', 'style']


class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)

    class Meta:
        model = User
        fields = ['url', 'id', 'username', 'snippets']

新しい'highlight'フィールドも追加したことに注意してください
このフィールドは
'snippet-highlight'URLパターンを指し示すこと以外、(通常の)urlフィールドと同じ型であり、'snippet-detail'の代わりです。

私たちのAPIには'.json'などのフォーマット接尾語URLが使えるため、highlightフィールド上で、highlightフィールドが返すどの形式の接尾語付きハイパーリンクが'.html'接尾語を使うべきかを指示する必要がある。
(※訳注:文法の解釈ミスがあるかも)


URLパターンに名前を付けているか確認する

ハイパーリンクされたAPIを使用する場合は、URLパターンに名前を付ける必要があります。
名前を付ける必要のあるURLパターンを見てみましょう。

  • 私たちのAPIのルートは'user-list''snippet-list'を参照する。
  • スニペットシリアライザーには、'snippet-highlight'を参照するフィールドが含まれている。
  • ユーザーシリアライザーには、'snippet-detail'を参照するフィールドが含まれている。
  • スニペットとユーザーシリアライザーには、'url'フィールドが含まれており、デフォルトで'{model_name}-detail'を参照する。今回は、'snippet-detail''user-detail'である。


これらすべての名前をURLconfに追加すると、最終的な
snippets/urls.pyファイルは次のようになります。

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

# API endpoints
urlpatterns = format_suffix_patterns([
    path('', views.api_root),
    path('snippets/',
        views.SnippetList.as_view(),
        name='snippet-list'),
    path('snippets/<int:pk>/',
        views.SnippetDetail.as_view(),
        name='snippet-detail'),
    path('snippets/<int:pk>/highlight/',
        views.SnippetHighlight.as_view(),
        name='snippet-highlight'),
    path('users/',
        views.UserList.as_view(),
        name='user-list'),
    path('users/<int:pk>/',
        views.UserDetail.as_view(),
        name='user-detail')
])


ページネーション

ユーザーのリストビューとコードスニペットは、非常に多くのインスタンスを返す可能性があるため、結果をページ分割し、APIクライアントが個々のページをステップスルーできるようにする必要があります。

tutorial/settings.pyファイルを少し変更することで、ページネーションを使用するように、デフォルトのリストスタイルを変更できます。次の設定を追加します。

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

RESTフレームワークの設定はすべて、REST_FRAMEWORKという名前の単一のディクショナリ設定に名前空間が設定されていることに注意してください。
これにより、他のプロジェクト設定から十分に分離できます。

必要に応じてページネーションスタイルをカスタマイズすることもできますが、今回はデフォルトのままにします。


APIの閲覧

ブラウザを開いてブラウザから閲覧可能なAPIに移動すると、リンクをたどるだけの労力でAPIを巡回できることがわかります。

スニペットインスタンスの「ハイライト」リンクも表示され、ハイライトされたコードのHTML表現に移動します。

チュートリアルのパート6では、APIを構築するために必要なコードの量を減らすため、ビューセット(ViewSet)とルータ(Router)を使用する方法を見ていきます。

0 件のコメント:

コメントを投稿

【和訳】Django Rest Framework 目次

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