REST
- REST是REpresentationsal State Transfer的缩写,具象状态转换
- RESTful是一种开发理念,是一种API设计风格,而不是标准
主要的规范
- 每一个URL代表一种资源,具体要对资源进行什么操作,是根据请求方式来区分的,而不是在URL上直接体现:
GET http://www.xxx.com/get_user/01
(不安全、繁琐、难维护等弊端),可以设计成GET http://www.xxx.com/user/01
- 后端返回的资源数据类型有:
1.json格式数据
2.text文本
3.图片、视频等 - 客户端和服务器之间,传递这种资源的某种表现形式
1.后端通过请求头Content-Type
来指明传给服务端的参数类型,比如application/json
2.客户端通过请求头中Accept
来指明希望后端返回的相应数据的类型,比如application/json
- 客户端通过请求方式的不同,指明对服务器资源进行不同的操作
1.GET:read
2.POST:create
3.PUT:update/replace
4.PATCH:partial/update/modify
5.DELETE:delete
REST常用的设计规范
一、URL
1.命名
- 尽量使用名词复数形式
- 往往与数据库的表名对应
2.过滤条件
- 如果记录数量很多,则需添加条件进行限制,否则返回数据太多,影响性能
?limit = 10 # 指定返回记录的数量
?offset = 10 # 指定返回记录的开始位置
?currPage=2&pageSize=10 # 指定第几页和每页多少条数据
?sort=name # 指定返回结果按照指定的属性进行排序
3.域名
- 尽量使用专用域名
http
4.版本号
- 在url中呈现版本号
http://xxx/app/1.0/
http://xxx/app/1.1/
- 也可以在请求头呈现
Accept:application/vnd.example.v1.0+json
Accept:application/vnd.example.v1.1+json;version=1.1
二、请求方式/动词
- 常见的http请求(括号中对应的sql命令)
GET(select):从服务器获取资源(一个或多个)
POST(create):在服务器创建一个资源
PUT(update):在服务器更新资源(客户端提供所要更新的完整资源,比如要更新user的age,但如果是put,需要提供user的全部数据)
DELETE(delete):从服务器删除资源 - 下面是不常见的三种
PATCH(update where):在服务器进行部分资源的更新(客户端提供改变的属性)
HEAD:获取资源的元数据
OPTIONS:获取关于资源的哪些属性是客户端可以改变的信息,一般后面会跟其它常用请求;比如特殊的post请求前会先发出options请求 - 例子
GET /projects # 获取所有项目信息
POST /projects # 创建一个新项目
GET / projects/6 # 获取id=6的项目信息
PUT /projects/6 # 更新id=6的项目信息(全更新)
PATCH /projects/6 # 更新id=6的项目信息(部分更新)
DELETE /projects/6 # 删除id=6的项目
''' 多层级信息的获取的设计 '''
GET /projects/6/interfaces # 获取id=6的项目信息中所有的接口信息
GET /projects/6/interfaces/1 #获取id=6的项目信息中id=1的接口信息
3、常见状态码(RESTful)
200 ok - [GET]:服务器成功返回用户请求的数据
201 CREATED - [POST/PUT/PATCH]:用户创建成功或修改数据成功
204 NO CONTENT - [DELETE]:用户删除数据成功
400 INVALID REQUEST - [POST/PUT/PATCH]:用户请求有误(请求参数有问题)
401 Unauthorized = [^] :表示用户没有权限(cookies、用户名、密码错误)
403 Forbidden - [^]:表示用户得到授权(和401错误相对),但是访问是禁止的
404 NOT FOUND - [^]:表示用户请求的路径不存在
500 INTERNAL SERVER ERROR - [^]:服务器发生错误
4、返回结果要求(RESTful)
- 服务器的响应数据应该符合以下规范
GET /projects # 返回所有项目信息的列表(json数组)
GET / projects/6 #返回一个项目的列表 (一个json)
POST /projects # 返回新生成的项目的列表 (一个json)
PUT /projects/6 # 返回更新之后,完整的项目信息(一个json)
PATCH /projects/6 # 返回更新之后,完整的项目信息(一个json)
DELETE /projects/6 # 删除id=6的项目 # 返回空
5、错误处理
- 当请求有误时,服务器需将错误信息以json的格式返回,比如
{
"code":1001,
"data":null,
"msg":"用户不存在"
}
6、超链接API
- 响应数据中,可以包含下一步操作的url链接(比如说上一页、下一页的链接字段)
传统编写CRUD
1.已有代码
- 已经创建好的model
- login/models.py
from django.db import models
class User(models.Model):
gender = (
('male', '男'),
('female', '女')
)
name = models.CharField(max_length=128, unique=True) # 昵称唯一
password = models.CharField(max_length=256)
email = models.EmailField(unique=True)
sex = models.CharField(max_length=32, choices=gender, default='女')
c_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
ordering = ['-c_time']
verbose_name = '用户'
verbose_name_plural = '用户'
- Django_Project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('login.urls'))
]
2.创建对项目数据进行CRUD操作的接口
- login/views.py
from login.serializer import UserModelSerializer
from rest_framework.viewsets import ModelViewSet
from django.http import JsonResponse
from login.models import User
from django.views import View
import json
class Users(View):
def get(self, request): # get请求中,就算用不上request,也需要设置这个参数
"""获取所有的User信息,返回类型为json"""
# 1.数据库中获取所有的项目信息
user_qs = User.objects.all()
user_list = []
# 2.遍历返回的查询集,同一个查询集的内容组装成json,并且所有的json都存放在一个列表中
for user in user_qs:
user_list.append(
# 序列化:把变量从内存中变成可存储或传输的过程(比如dump/dumps、把数据转成json/把数据写入内存)
{
'name': user.name,
'password': user.password,
'email': user.email,
'sex': user.sex,
'c_time': user.c_time
}
)
# JsonResponse()第一个参数需要是dict,否则需要指定safe=False,不然报错
return JsonResponse(user_list, safe=False, status=200)
def post(self, request):
""" 新创建User """
# 1.获取请求中body的值,并解码
user = request.body.decode('utf8') # 注意body是属性,不是方法,不需要()
# 2.还需要判断是否是json,并且必参是否填写(此处略过,痛点之一)
# 3.把json数据反序列化成python类型的dict
user_dict = json.loads(user, encoding='utf8')
# 4.创建新的User到数据库中
user = User.objects.create(**user_dict)
# 5.新生成的user转成json(也称为序列化)
user_new = {
'name': user.name,
'password': user.password,
'email': user.email,
'sex': user.sex,
'c_time': user.c_time
}
# 6.响应返回
return JsonResponse(user_new, status=201)
class UserDetail(View):
def get(self, request, pk):
""" 根据id=pk查询(pk是django默认创建的主键,和id一样) """
# 1.此处用get对id进行查询,因为主键唯一,只会返回一个值
# 此处应该对pk进行int判断,略过,痛点之一
user = User.objects.get(id=pk)
# 2.序列化,转成json
user_dict = {
'name': user.name,
'password': user.password,
'email': user.email,
'sex': user.sex,
'c_time': user.c_time
}
# 3. 响应
return JsonResponse(user_dict, status=200)
def put(self, request, pk):
""" 根据id查询user,并更新改user的全部信息;请求中需有id和user更新后的全部信息 """
# 1.此处用get对id进行查询,因为主键唯一,只会返回一个值
# 此处应该对pk进行int判断,略过,痛点之一
old_user = User.objects.get(id=pk)
# 2.获取请求中修改后的user的信息,并反序列化成python的dict
user_dict = request.body.decode('utf8')
# 3.更新为新的user信息(因为是全部字段都更新,所以不使用update)
# 3.1.反序列化
user_value = json.loads(user_dict, encoding='utf8')
# 3.2.替换值
old_user.name = user_value['name']
old_user.password = user_value['password']
old_user.email = user_value['email']
old_user.sex = user_value['sex']
old_user.c_time = user_value['c_time']
# 3.3.保存
old_user.save()
# 4.新user序列化
user_data = {
'name': old_user.name,
'password': old_user.password,
'email': old_user.email,
'sex': old_user.sex,
'c_time': old_user.c_time
}
# 5.响应
return JsonResponse(user_data, status=201)
def delete(self, request, pk):
"""根据id=pk进行删除操作 ORM的删除是先查询再删除"""
# 1.查询
# 此处应该对pk进行int判断,略过,痛点之一
user = User.objects.get(id=pk)
# 2.删除
user.delete()
# 3.响应{}
return JsonResponse({}, safe=False, status=204)
- login.urls.py
from django.urls import path
from login import views
app_name = 'login'
urlpatterns = [
path(r'users/', views.Users.as_view()),
path(r'users/<int:pk>/', views.UserDetail.as_view()),
]
设计总结
1.序列化
- 首先思考下:内存中的字典、列表、集合以及各种对象,如何保存到一个文件中?
1.设计一套协议,按照某种规则,把内存中的数据保存到文件中,文件是一个个字节序列。所以必须把数据额转换为字节序列,输出到文件,这就是序列化,反之,从文件的字节 序列恢复到内存中,就是反序列化。
2.反序列化则相反 - 序列化在
Json
中:
1.json().dump
:把数据转成json格式字符串并写入文件
2.json().dumps
:读取文件数据,并转成json格式字符串
2.增删改查的步骤
- 增
校验请求参数 -> 反序列化查询到的数据 -> 保存数据 -> 将保存的对象序列化并返回 - 删
判断要删除的数据是否存在 -> 执行数据删除 - 改
判断要修改的数据是否存在 -> 校验请求参数 -> 反序列化查询到的数据 -> 保存数据 -> 将保存的数据序列号并返回 - 查
查询数据库 -> 将查询到的数据序列化并返回
痛点
- 代码冗余极其严重,不符合优开发风格(代码能少写就少写)
- 数据校验非常麻烦,且可复用性差
- 编码没有统一的规范,杂乱无章的感觉
- 仅支持json格式的传参,不支持form表单传参
- 仅能返回json格式的数据,其他类型不支持
- 列表页视图没有分页,过滤,排序功能
网友评论