测试开发进阶(二十四)

测试开发进阶(二十四)

欢迎关注我的公众号「测试游记」

REST API

官方文档:https://restfulapi.net/

一种开发理念「是设计风格 而不是标准」

REST is acronym for REpresentational State Transfer.

每一个URL代表一种「资源

具体要对资源做什么操作,要体现在请求方式上,而不是URL上

  • json格式数据
  • text文本
  • 图片,视频等

客户端和服务器之间,传递这种资源的某种表现形式

  • 通过请求头中的Content-Type来指明传给服务端的参数类型

text/plain

application/xml

text/html

application/json

image/gif

image/jpeg

Application/x-www-form-urlencoded

  • 通过请求头中Accept来指明希望接受服务端的数据类型

Accept:application/json,application/xml;q=0.9,*/*;q=0.8

  • POST:创建「create」
  • GET:获取「read」
  • PUT:更新,替换「update/replace」
  • PATCH:部分更新「Partial update/modify」
  • DELETE:删除「delete」

设计规则

命名

  • 尽量使用名词复数形式
  • 往往与数据库的表名对应

过滤条件

一般记录数量较多,服务器不可能将所有数据都返回给前端

例如:

1
2
?page=2&size=10 指定页数,条数
?sort=name 指定排序

域名

尽量使用专用域名

前后端分离之后,前后端都有一个域名

例如http://api.xxx.xxx

版本

  • 在url中呈现版本号
1
http://api.xxx.xxx/app/0.1
  • 在请求头中呈现
1
2
Accept: application/vnd.example.v0.2+json
Accept: application/vnd.example+json;version=1.1

常见请求含义

  • GET(SELECT):从服务器获取资源(一项或多项)
  • POST(CREATE):从服务器新建一个资源
  • PUT(UPDATE):从服务器更新资源(客户端提供改变后的完整资源)
  • DELETE(DELETE):从服务器删除资源
  • PATCH(UPDATE WHERE):在服务器部分更新资源(客户端提供改变的属性)
  • HEAD:获取资源的元数据
  • OPTIONS:获取关于资源的哪些属性是客户端可以改变的信息

状态码

  • 200:OK

「GET」服务器成功返回用户请求的数据

  • 201:CREATED

「POST/PUT/PATCH」用户新建或修改数据成功

  • 204:NO CONTENT

「DELETE」用户删除数据成功

  • 400:INVALID REQUEST

「POST/PUT/PATCH」用户请求有误(请求参数有误)

  • 401:Unauthorized

「*」用户没有权限(令牌,用户名,密码错误)

  • 403:Forbidden

「*」表示用户得到授权(与401错误相对),但是访问是被禁止的

  • 404:NOT FOUND

「*」用户请求路径不存在

  • 500:INTERNAL SERVER ERROR

「*」服务器发生错误

接口设计

最原始设计

GET

  1. 从数据库中获取所有的项目信息
  2. 将数据库模型实例转化为字典类型「Json数组」「嵌套字典的列表」
  3. 注意:JsonResponse第一个参数默认只能为dict字典,如果要设为其他类型,需要将safe设为False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# LearnDjango/projects/views.py
from django.http import JsonResponse
from projects.models import Projects
from django.views import View


class ProjectsList(View):
def get(self, reuqest):
# 1.从数据库中获取所有的项目信息
project_qs = Projects.objects.all()
# 2.将数据库模型实例转化为字典类型「Json数组」「嵌套字典的列表」
project_list = []
for project in project_qs:
project_list.append(
{
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
)
# JsonResponse第一个参数默认只能为dict字典,如果要设为其他类型,需要将safe设为False
return JsonResponse(project_list, safe=False)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# LearnDjango/projects/urls.py
from django.urls import path
from projects import views

urlpatterns = [
path('project/', views.ProjectsList.as_view()),
]


# LearnDjango/urls.py
from django.contrib import admin
from django.urls import path, include, re_path

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('projects.urls'))
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ http http://127.0.0.1:8000/project/
zhongxindeMacBook-Pro:~ zhongxin$ http http://127.0.0.1:8000/project/
HTTP/1.1 200 OK
Content-Length: 650
Content-Type: application/json
Date: Fri, 11 Oct 2019 13:02:56 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN

[
{
"desc": "666",
"leader": "zx_94",
"name": "测试游记",
"programer": "zhong",
"publish_app": "公众号",
"tester": "zx"
},
{
"desc": "6666",
"leader": "zx_94_1",
"name": "测试游记1",
"programer": "zhong1",
"publish_app": "公众号1",
"tester": "zx1"
},
{
"desc": "666",
"leader": "zx_94",
"name": "「测试游记」-创建",
"programer": "zx",
"publish_app": "公众号",
"tester": "zx"
},
{
"desc": "666",
"leader": "钟鑫",
"name": "10月1日作业",
"programer": "钟鑫",
"publish_app": "国庆作业",
"tester": "钟鑫"
}
]

GET

POST

  1. 从前端获取json格式的数据,转化为Python中的类型

为了严谨性,这里需要做各种复杂的校验

比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带

  1. 向数据库中新增项目
  2. 将模型类转化为字典,然后返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def post(self, request):
"""
新建项目
"""
# 1.从前端获取json格式的数据,转化为Python中的类型
# 为了严谨性,这里需要做各种复杂的校验
# 比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
# 2.向数据库中新增项目
project = Projects.objects.create(**python_data)
# 3.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ http POST http://127.0.0.1:8000/project/ name=10月11日「测试游记」 leader=zx tester=zx programer=zx publish_app=10月11日内容 desc=测试post请求
zhongxindeMacBook-Pro:~ zhongxin$ http POST http://127.0.0.1:8000/project/ name=10月11日「测试游记」 leader=zx tester=zx programer=zx publish_app=10月11日内容 desc=测试post请求
HTTP/1.1 200 OK
Content-Length: 202
Content-Type: application/json
Date: Fri, 11 Oct 2019 13:31:46 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN

{
"desc": "测试post请求",
"leader": "zx",
"name": "10月11日「测试游记」",
"programer": "zx",
"publish_app": "10月11日内容",
"tester": "zx"
}

POST

查看数据库

GET具体内容

  1. 校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
  2. 获取指定pk值的项目
  3. 将模型类转化为字典,然后返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# projects/views.py
class ProjectDetail(View):
def get(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
# 3.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict)
1
2
3
4
5
6
7
8
# projects/urls.py
from django.urls import path
from projects import views

urlpatterns = [
path('project/', views.ProjectsList.as_view()),
path('project/<int:pk>/', views.ProjectDetail.as_view()),
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ http :8000/project/1/
zhongxindeMacBook-Pro:~ zhongxin$ http :8000/project/1/
HTTP/1.1 200 OK
Content-Length: 145
Content-Type: application/json
Date: Fri, 11 Oct 2019 13:42:44 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN

{
"desc": "666",
"leader": "zx_94",
"name": "测试游记",
"programer": "zhong",
"publish_app": "公众号",
"tester": "zx"
}

GET具体内容

PUT具体内容

  1. 校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
  2. 获取指定pk值的项目
  3. 从前端获取json格式的数据,转化为Python中的类型

为了严谨性,这里需要做各种复杂的校验

比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带

  1. 更新项目
  2. 将模型类转化为字典,然后返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def put(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
# 3.从前端获取json格式的数据,转化为Python中的类型
# 为了严谨性,这里需要做各种复杂的校验
# 比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
# 4.更新项目
project.name = python_data['name']
project.leader = python_data['leader']
project.tester = python_data['tester']
project.programer = python_data['programer']
project.publish_app = python_data['publish_app']
project.desc = python_data['desc']
project.save()
# 5.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict, status=201)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ http PUT :8000/project/5/ name=10月11日「测试游记」 leader=zhongxin tester=zx programer=zx publish_app=10月11日内容 desc=测试post请求
zhongxindeMacBook-Pro:~ zhongxin$ http PUT :8000/project/5/ name=10月11日「测试游记」 leader=zhongxin tester=zx programer=zx publish_app=10月11日内容 desc=测试post请求
HTTP/1.1 201 Created
Content-Length: 208
Content-Type: application/json
Date: Fri, 11 Oct 2019 13:53:49 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN

{
"desc": "测试post请求",
"leader": "zhongxin",
"name": "10月11日「测试游记」",
"programer": "zx",
"publish_app": "10月11日内容",
"tester": "zx"
}

PUT

修改后

DELETE

  1. 校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
  2. 获取指定pk值的项目
  3. 删除
1
2
3
4
5
6
def delete(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
project.delete()
return JsonResponse({}, safe=True, status=204)
1
2
3
4
5
6
7
8
9
$ http DELETE :8000/project/6/
zhongxindeMacBook-Pro:~ zhongxin$ http DELETE :8000/project/6/
HTTP/1.1 204 No Content
Content-Length: 2
Content-Type: application/json
Date: Fri, 11 Oct 2019 14:03:45 GMT
Server: WSGIServer/0.2 CPython/3.7.1
Vary: Origin
X-Frame-Options: SAMEORIGIN

DELETE

原始设计小结

创建接口的任务

  1. 校验用户数据
  2. 将请求的数据(如json格式)转换为模型类对象

反序列化

  • 将其他格式(json,xml等)转换为程序中的数据类型
  • 将json格式的字符串转换为Django中的模型类对象
  1. 操作数据库
  2. 将模型类对象转换为响应的数据(如json格式)

序列化

  • 将程序中的数据类型转换为其他格式(json,xml等)
  • 例如将Django中的模型类对象转换为json字符串

数据增删改查流程

校验请求参数 -> 反序列化 -> 保存数据 -> 将保存的对象序列化并返回

判断要删除的数据是否存在 -> 执行数据删除

判断要修改的数据是否存在 -> 校验请求参数 -> 反序列化 -> 保存数据 -> 将保存的数据序列号并返回

查询数据库 -> 将数据序列化并返回

原始设计代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import json
from django.http import JsonResponse
from projects.models import Projects
from django.views import View


class ProjectsList(View):
def get(self, reuqest):
# 1.从数据库中获取所有的项目信息
project_qs = Projects.objects.all()
# 2.将数据库模型实例转化为字典类型「Json数组」「嵌套字典的列表」
project_list = []
for project in project_qs:
project_list.append(
{
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
)
# JsonResponse第一个参数默认只能为dict字典,如果要设为其他类型,需要将safe设为False
return JsonResponse(project_list, safe=False)

def post(self, request):
"""
新建项目
"""
# 1.从前端获取json格式的数据,转化为Python中的类型
# 为了严谨性,这里需要做各种复杂的校验
# 比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
# 2.向数据库中新增项目
project = Projects.objects.create(**python_data)
# 3.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict)


class ProjectDetail(View):
def get(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
# 3.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict)

def put(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
# 3.从前端获取json格式的数据,转化为Python中的类型
# 为了严谨性,这里需要做各种复杂的校验
# 比如:是否为json,传递的项目数据是否符合要求,有些必传参数是否携带
json_data = request.body.decode('utf8')
python_data = json.loads(json_data, encoding='utf8')
# 4.更新项目
project.name = python_data['name']
project.leader = python_data['leader']
project.tester = python_data['tester']
project.programer = python_data['programer']
project.publish_app = python_data['publish_app']
project.desc = python_data['desc']
project.save()
# 5.将模型类转化为字典,然后返回
one_dict = {
'name': project.name,
'leader': project.leader,
'tester': project.tester,
'programer': project.programer,
'publish_app': project.publish_app,
'desc': project.desc
}
return JsonResponse(one_dict, status=201)

def delete(self, request, pk):
# 1.校验前端传递的pk(项目ID)值,类型是否正确(正整数),在数据库中是否存在等「先省略」
# 2.获取指定pk值的项目
project = Projects.objects.get(id=pk)
project.delete()
return JsonResponse({}, safe=True, status=204)
 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
您的支持将鼓励我继续创作!