RESTful风格API

1.RESTful风格API

详情查看博客地址:https://www.cnblogs.com/xiaonq/p/10053234.html

1.1 什么是RESTful

  • REST与技术无关,代表的是 一种软件架构风格 (REST是Representational State Transfer的简称,中 文翻译为“表征状态转移”)

  • REST从资源的角度类审视整个网络,它将分布在网络中某个节点的 资源通过URL进行标识

  • 所有的数据,不过是通过网络获取的还是 操作(增删改查) 的数据,都是资源,将一切数据视为资 源是REST区别与其他架构风格的最本质属性

  • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA: Resource Oriented Architecture)

2.RESTful API设计规范

  • 1.API与用户的通信协议,总是使用HTTPs协议。

  • 2.域名

# 1)子域名方式
https://api.example.com # 尽量将API部署在专用域名(会存在跨域问题)
https://www.example.com # vue前端域名
# 2)url方式
https://example.org # vue前端域名
https://example.org/api/ # 后端API域名(不存在跨域)
  • 3.版本


URL,如:https://api.example.com/v1/
请求头 跨域时,引发发送多次请求
  • 4.面向资源编程 : 路径,视网络上任何东西都是资源,均使用名词表示(可复数)


https://api.example.com/v1/zoos/1/
https://api.example.com/v1/animals
https://api.example.com/v1/employees
  • 5.method


GET(查询数据) # 从服务器取出资源(一项或多项)
POST(创建数据) # 在服务器新建一个资源
PUT(修改数据) # 在服务器更新资源(客户端提供改变后的完整资源)
PATCH(修改属性) # 在服务器更新资源(客户端提供改变的属性)
DELETE(删除数据) # 从服务器删除资源
  • 6.过滤,分页,排序 :通过在url上传参的形式传递搜索条件

https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,
以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
  • 7.状态码


'''1. 2XX请求成功'''
# 1.1 200 请求成功,一般用于GET与POST请求
# 1.2 201 Created - [POST/PUT/PATCH]:用户新建或修改数据成功。
# 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
# 204 NO CONTENT - [DELETE]:用户删除数据成功。
'''2. 3XX重定向'''
# 301 NO CONTENT - 永久重定向
# 302 NO CONTENT - 临时重定向
'''3. 4XX客户端错误'''
# 3.1 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误。
# 3.2 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
# 3.3 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
# 3.4 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录。
# 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格
式)。
# 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
# 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
'''4. 5XX服务端错误'''
# 500 INTERNAL SERVER ERROR - [*]:服务器内部错误,无法完成请求
# 501 Not Implemented 服务器不支持请求的功能,无法完成请求
更多状态码参考:https://www.runoob.com/http/http-status-codes.html

 

## django实现restful
```python
# urls.py
urlpatterns = [
url(r'^users', Users.as_view()),
]
# views.py
from django.views import View
from django.http import JsonResponse

class Users(View):
def get(self, request, *args, **kwargs):
result = {
'status': True,
'data': 'response data'
}
return JsonResponse(result, status=200)

def post(self, request, *args, **kwargs):
result = {
'status': True,
'data': 'response data'
}
return JsonResponse(result, status=200)
```
## 基于drf框架实现
## 1.serializer-APIView
```python
# models.py
class Classroom(models.Model):
"""
班级表
"""
class_name = models.CharField(max_length=32, verbose_name="班级名称", unique=True)
address = models.CharField(max_length=32, null=True)
class Meta:
db_table = "pp_class"
def __str__(self):
return self.class_name

# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.class_name = validated_data.get('class_name', instance.class_name)
instance.address = validated_data.get('address', instance.address)
instance.save()
return instance

# views.py
class ClassroomView(APIView):
def get(self, request):
# 查询
class_obj = Classroom.objects.all().order_by('-id')
ser_obj = ClassroomSerializer(class_obj , many=True)
return Response(ser_obj.data)
def post(self, request):
# 添加
data = request.data
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
def put(self, request):
# 修改
data = request.data
instance = Classroom.objects.filter(class_name=data['class_name']).first() # 查询要修改的对象
ser_obj = ClassroomSerializer(instance=instance, data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
```

 

 

## 添加时数据自定义验证
方法一:在views中验证
```python
# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
# views.py
class ClassroomView(APIView):
def post(self, request):
data = request.data
# 验证地址 是不是 beijing
if data['address'] != 'beijing':
return Response({'msg': '信息不在北京'})
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
```
方法二:序列化中验证
```python
# serializer.py
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
def create(self, validated_data):
return Classroom.objects.create(**validated_data)
# 自定义验证规则
def validate(self, attrs):
if attrs.get('address') != 'beijing':
raise serializers.ValidationError('信息不在北京')
return attrs
# views.py
class ClassroomView(APIView):
def post(self, request):
data = request.data
ser_obj = ClassroomSerializer(data=data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
```
## 多对多一对多序列化嵌套
```python
# models.py
from django.db import models
class Role(models.Model):
"""
角色表
"""
role_name = models.CharField(max_length=32, unique=True)
class Meta:
db_table = "pp_role"
class Classroom(models.Model):
"""
班级表
"""
class_name = models.CharField(max_length=32, verbose_name="班级名称", unique=True)
address = models.CharField(max_length=32, null=True)
class Meta:
db_table = "pp_class"
def __str__(self):
return self.class_name
class User(models.Model):
"""
用户表
"""
username = models.CharField(max_length=32, verbose_name="姓名")
age = models.IntegerField(verbose_name="年龄")
home = models.CharField(verbose_name="家乡", null=True, max_length=32)
hight = models.IntegerField(verbose_name="身高", null=True)
# 多对多
roles = models.ManyToManyField(Role)
# 一对多
classrooms = models.ForeignKey(Classroom, on_delete=models.CASCADE, null=True)
class Meta:
db_table = "pp_user"
# serializer.py
from rest_framework import serializers
from .models import *
class ClassroomSerializer(serializers.Serializer):
class_name = serializers.CharField(max_length=32, required=True, label='班级名')
address = serializers.CharField(max_length=32, label='地址')
class RoleSerializer(serializers.Serializer):
role_name = serializers.CharField(max_length=32, required=True, label='角色名')
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=32)
age = serializers.IntegerField()
home = serializers.CharField(max_length=32, allow_null=True)
hight = serializers.IntegerField(allow_null=True)
# 多对多
roles = RoleSerializer(many=True)
# 一对多
classrooms = ClassroomSerializer()

# views.py
# 查询用户
class UserView(APIView):
def get(self, request):
# 查询
user_obj = User.objects.all()
ser_obj = UserSerializer(user_obj, many=True)
return Response(ser_obj.data)
```
查询结果:
```python
[
{
"username": "张三",
"age": 22,
"home": "北京",
"hight": 180,
"roles": [
{
"role_name": "教师"
},
{
"role_name": "警察"
}
],
"classrooms": {
"class_name": "2002A",
"address": "北京"
}
},
{
"username": "李四",
"age": 33,
"home": "啊啊",
"hight": 180,
"roles": [
{
"role_name": "教师"
}
],
"classrooms": {
"class_name": "2002B",
"address": "beijing"
}
},
{
"username": "王五",
"age": 22,
"home": "北京",
"hight": 180,
"roles": [],
"classrooms": {
"class_name": "2002c",
"address": "beij"
}
}
]
```
## 用户访问次数/频率限制
全局使用
```python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
```

 

 

## 分页
```python
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from .serializer import *
class PageNum(PageNumberPagination):
# 指定查询字符串中代表每页返回数据数量的参数名,默认None
page_size_query_param = "max_page"
# 指定查询字符串中代表页码的参数名,不指定默认值page
# page_query_param = 'page'
# max_page_size = 10 # 一页最多的结果条数,
class ClassroomView(APIView):
def get(self, request):
class_obj = Classroom.objects.all().order_by('-id')
# 分页
paginator = PageNum()
result_page = paginator.paginate_queryset(class_obj, request)
ser_obj = ClassroomSerializer(result_page, many=True)
return Response(ser_obj.data)
```

posted @ 2020-10-28 16:05  Aurora.🌻  阅读(58)  评论(0编辑  收藏  举报