I am getting frustrated by the number of people calling any HTTP-based interface a REST API. Today’s example is the SocialSite REST API. That is RPC. It screams RPC. There is so much coupling on display that it should be given an X rating.
What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period. Is there some broken manual somewhere that needs to be fixed?
— Roy Fielding
https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
我的理解是,像超文本一样携带一个地址,可以寻址定位信息,如超文本的link属性。
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}
摘取自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
snippets
和users
创建了Endpoint,现在来创建根目录的Endpoint,编辑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)
})
reverse()
函数用来返回snippets/urls.py
中viewname对应的url,如path('users/', views.UserList.as_view(), name='user-list')
。
snippets/urls.py
中:path('', views.api_root),
Snippet.highlighted
字段么: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)
snippets/urls.py
中:path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view()),
因为 snippet.highlighted
不是JSON而是HTML,所以用[renderers.StaticHTMLRenderer]
返回预渲染的(pre-rendered)HTML。
主键
超链接
关系实体(the related entity),唯一标识符字段(a unique identifying slug field)
关系实体,默认字符串(the default string representation)
关系实体,嵌入到父类中(the parent representation)
其他自定义
前2个比较熟悉,后面几个有点不太懂,我理解是类似于数据库的关联关系表。
HyperlinkedModelSerializer
来实现真正的RESTful。在snippets/serializers.py
中把我们之前的代码:class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner']
class UserSerializer(serializers.ModelSerializer):
snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())
class Meta:
model = User
fields = ['id', 'username', 'snippets']
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']
ModelSerializer
换成了HyperlinkedModelSerializer
,后者的区别如下:默认不包含id
字段
包含url
字段,用HyperlinkedIdentityField
表示
源码:
serializer_url_field = HyperlinkedIdentityField
关系用HyperlinkedRelatedField
表示,而不是PrimaryKeyRelatedField
源码:
serializer_related_field = HyperlinkedRelatedField
'{model_name}-detail'
url pattern,这是DRF定义的,在示例中就是'snippet-detail'
和'user-detail'
。新增的highlight
字段和url
字段是一样的类型,它指向的是'snippet-highlight'
,而不是'snippet-detail'
。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')
])
name就是在 serializers.py
和views.py
中用到的。
tutorial/settings.py
文件:REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
HyperlinkedModelSerializer
来实现,还是比较好理解的,其中的细节需要在实战中再多多熟悉。参考资料: https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/ https://spring.io/guides/tutorials/rest/
联系客服