使用Flask设计实现一套API【成绩管理系统】
0X00 什么是REST风格的API
众所周知http协议有GET/PUT/POST/PATCH/DELETE
等众多方法,还能在提交请求和发送响应的时候携带数据。REST风格的API就是使用了这些HTTP特性的API。针对一个URL可以有多种动词(方法)来表示不同的操作。
更多详细的内容可以点击查看阮一峰的博客:理解RESTful架构
0X01 怎么选用HTTP动词
常见的动词有这五种,可以对应自己的需求选用
动词 | 类似的SQL关键字 | 功能 |
---|---|---|
GET | SELECT | 获取资源 |
POST | CREATE | 创建资源 |
PUT | UPDATE | 更新资源(需要提供改变后的完整资源) |
PATCH | UPDATE | 更新资源(需要提供改变的属性) |
DELETE | DELETE | 删除资源 |
0X02 设计URL
REST风格的API因为可以用HTTP的动词,所以URL中是不带有动词的,如果我要获取某个学生的信息应该是[GET] http://api.example.com/student/id=12345678900
。HTTP动词理论上是能满足各种情况下的需求的,所以URL中只应该出现名词而不应该出现动词。这里用阮一峰举的例子来说明一下
| 动词 | 路径 | 功能 |
| –|— |
| GET | /zoos | 列出所有动物园 |
| POST | /zoos | 新建一个动物园 |
| GET | /zoos/ID | 获取某个指定动物园的信息 |
| PUT | /zoos/ID | 更新某个指定动物园的信息(提供该动物园的全部信息) |
| PATCH | /zoos/ID | 更新某个指定动物园的信息(提供该动物园的部分信息) |
| DELETE | /zoos/ID | 删除某个动物园 |
| GET | /zoos/ID/animals | 列出某个指定动物园的所有动物 |
| DELETE | /zoos/ID/animals/ID | 删除某个指定动物园的指定动物 |
0X03 状态码
状态码是HTTP中的一大优势,一个响应可以只靠状态码来判请求结果。这些是常见的状态码,自己设计API的时候要严格按照规范来设计状态码,可以提高代码和API的可读性和可理解性。
状态码 | 信息 | 请求类型 | 含义 |
---|---|---|---|
200 | OK | [GET] | 服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 |
201 | CREATED | [POST/PUT/PATCH] | 用户新建或修改数据成功。 |
202 | Accepted | [*] | 表示一个请求已经进入后台排队(异步任务)。 |
204 | NO CONTENT | [DELETE] | 用户删除数据成功。 |
400 | INVALID REQUEST | [POST/PUT/PATCH] | 用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 |
401 | Unauthorized | [*] | 表示用户没有权限(令牌、用户名、密码错误)。 |
403 | Forbidden | [*] | 表示用户得到授权(与401错误相对),但是访问是被禁止的。 |
404 | NOT FOUND | [*] | 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 |
406 | Not Acceptable | [GET] | 用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 |
410 | Gone | [GET] | 用户请求的资源被永久删除,且不会再得到的。 |
422 | Unprocesable entity | [POST/PUT/PATCH] | 当创建一个对象时,发生一个验证错误。 |
500 | INTERNAL SERVER ERROR | [*] | 服务器发生错误,用户将无法判断发出的请求是否成功。 |
0X04 如何用Python实现
Python有大量第三方库可以实现REST风格的API,我这里选用的是相对轻量化的一个 Flask。安装这个库最简单的方式还是用pip,根据环境变量的不同可能具体命令有所不同,在我的Linux上是用pip3 install flask
就可以直接安装好的。
安装好后进入Python的交互式界面输入import flask
如果没有出现Import Error
就是安装好了。
0X05创建数据库和表
现在可以开始设计API了。既然是成绩管理系统,那么首先就要创建一个数据库,我这里的数据库是用的MariaDB。
列名 | 类型 | 含义 | 键 |
---|---|---|---|
id | int | 编号 | 主键 |
name | varchar(10) | 学生姓名 | |
number | char(11) | 学号 | |
python | float | Py成绩 | |
cpp | float | c++成绩 | |
os | float | 操作系统成绩 | |
network | float | 计算机网络成绩 | |
total | float | 总分 | |
ave | float | 平均分 |
0X06 创建Py脚本
1 | from flask import Flask, request |
这段代码写好之后运行起来会在本地监听5000端口(默认的),然后当你用浏览器访问http://localhost:5000/
的时候就像你返回<h1>hello,world</h1>
,在浏览器页面下看到的就是一行大号的hello,world。因为在浏览器的地址栏输入URL按回车之后就是向那个URL发送了GET请求,也就正好调用了index()
方法。
这里先将与API无关的代码填好,下面开始正式完成各项功能。其实也就是连接了数据库而已
1 | from flask import Flask, request |
0X07 实现一个构造返回Json数据的方法
首先我们选择使用Json来作为数据传输格式,因为Json相对XML来说更轻量一点,现在也更流行。规定客户端每次请求会后服务器都会返回下面这样类型的Json数据
1 | { |
API提供增删查改功能,增删改只通过状态码就可以判断执行结果,只有查询的时候才会需要从响应中获取数据。
0X08 增加一条新的数据
添加一条新数据按照标准应该使用动词POST
,根据URL中只有名词不用动词只有名词的标准,隧将URL设计成http://localhost/student
,再依据标准添加版本号上去,变成http://localhost/v1/student
。
具体功能代码实现如下,
1 | # 路径为/v1/student,方法为POST |
0X09 删除已经存在的数据
根据标准,将API设计成DELETE
方法,URL为http://localhost/v1/student/number=<number>
第一行的number=<number>
可以将url中符合这种规范的匹配出来,配合方法定义时的参数,可以直接将url参数传入到方法体中。
1 | # 路径为/v1/student, 方法为DELETE |
0X0A 查询学生成绩
根据标准,将API设计成GET
方法,URL为http://localhost/v1/student/sort_by=<sort_by>
。提供了python/cpp/network/os/total/ave
排序方式,(其实是数据库实现的)。
1 |
|
0X0B 修改学生成绩
修改学生成绩和添加成绩几乎是一样的操作,只有这么几点是不太一样的。添加信息时如果学号已经存在了那就不能再添加了,而修改的时候是如果学号不存在才错误;添加和修改的SQL不同。就没有别的区别了。
1 |
|
0X0C 搞定所有API
现在就搞定了所有的API编写。现在我把所有代码贴上来,注意这段代码是用于Python3的。如果需要测试的话可以用Python自带的requests
模块或者Postman软件来测试该API。
- 声明:代码最后一行的
app.run()
方法,现在是只在本地监听的。可以改成app.run('0.0.0.0')
就对外部监听了。
1 | #!/usr/bin/env python3 |