Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

Gray-Ice

个人博客兼个人网站

本篇博客参考自官方文档:Quickstart

一个demo

首先,安装flask_restful包:

1
pip3 install flask_restful

然后请看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask
from flask_restful import Resource, Api


app = Flask(__name__)
api = Api(app)

class HelloWorld(Resource):
def get(self):
return {
'hello': 'world'
}


api.add_resource(HelloWorld, '/')


if __name__ == '__main__':
app.run(debug=True)

然后运行:

1
python3 yourfile.py

访问接口:

1
curl http://127.0.0.1:5000

然后能得到响应:

1
2
3
4
{
"hello": "world"
}

多方法

flask_restful能够使用多方法,如:get, post, put, delete。
那么下面是代码,一看就明白:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

todos = {}

class TodoSimple(Resource):
# Get方法
def get(self, todo_id):
return {todo_id: todos[todo_id]}
# Post方法
def post(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}

api.add_resource(TodoSimple, '/<string:todo_id>')

if __name__ == '__main__':
app.run(debug=True)

以下是用不同的方法请求接口返回的响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# POST方法请求接口,-d是携带的参数
curl http://localhost:5000/111 -d "data=Remember the fire" -X POST

# 返回的响应
{
"111": "Remember the fire"
}

# GET方式请求接口
curl http://localhost:5000/111
# 返回的响应
{
"111": "Remember the fire"
}

返回不同的响应码:

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
from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class Todo1(Resource):

def get(self):
# 默认返回状态码是200
return {
'task': 'Hello World'
}


class Todo2(Resource):
def get(self):
# 设置响应状态码为201
return {
'task': 'hello world'
}, 201


class Todo3(Resource):
def get(self):
# 设置响应码并返回定制的头部(这么翻译似乎有些不太妥当,但是鉴于博主的水平,只能翻译到这一步了)
# 原文是这么写的: Set the response code for 201 and return custom headers

return {
'task': 'Hello world'
},201,{
'Etag': 'some-opaque-string'
}

多个路由指向一个视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from flask import Flask, request
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)


class Hello(Resource):
def get(self):
return {
'msg': 'good'
}

# 匹配多个路由
api.add_resource(Hello, '/', '/hello')

if __name__ == '__main__':
app.run(debug=True)

这段代码执行后,无论是访问/,还是访问/hello,得到的响应都会是’msg’: ‘good’。

参数解析

如果不明白”参数解析”是什么意思的话,就将其当成验证参数就好。
使用flask_restful中的一个方法,可以判断参数的类型,如果参数的类型不对,就返回一个自定义的提醒。
那么下前请看代码:

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
from flask import Flask, request
from flask_restful import Resource, Api, reqparse

app = Flask(__name__)
api = Api(app)

# 定义解析规则
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate to charge for this resource')
class Hello(Resource):
def get(self):
return {
'msg': 'good'
}

def post(self):
# 解析
args = parser.parse_args()
return {
'msg': 'good'
}

api.add_resource(Hello, '/hello')
if __name__ == '__main__':
app.run(debug=True)

运行服务,访问接口,这里要注意我携带的参数:

1
2
# 这里我携带了一个字符串
curl -d 'rate=foo' http://127.0.0.1:5000/hello

得到的响应,这个响应有点怪,因为官方文档里还带了一个status:400,我的响应如下:

1
2
3
4
5
6
7
8
{
"message": {
"rate": "Rate to charge for this resource"
}
}

# 但是官方文档里的响应是:
{'status': 400, 'message': 'foo cannot be converted to int'}

这个响应就是我之前自定义的那个提醒,因为我设置的type为int类型,而’foo’明显是字符串,不是我所指定的类型,因此返回了提醒。
接下来再用int类型的参数请求一次:

1
2
# 参数是int类型
curl -d 'rate=1' http://127.0.0.1:5000/hello

成功得到响应:

1
2
3
4
{
"msg": "good"
}

数据格式化

这一内容的主要目的是返回一个对象。官方文档上只给出了代码,而且还不是全部代码,没有给出运行结果,就连名为”Full Example”标题下的内容里都没有与”Data Formatting”(数据格式化),这让理解能力奇差的我感到十分的难过。不过好在按照官方文档的代码写还是成功了。

最后我再放全部代码,那么接下来是第一步:导入模块。

1
from flask_restful import fields, marshal_with

看字面意思就知道,fields是字段的意思,不过这个marshal_with就让人有点难以理解了,但是不急,官方文档上说明了,这是个装饰器,而关于fields的作用,官方文档上是这么说的:”you use the fields module to describe the structure of your response.”,用我的垃圾英语来翻译的话,就是”使用字段模块来描述响应的结构体”。这个其实和Django的ORM差不多,那么我们先看代码。

1
2
3
4
resource_fields = {
'task': fields.String,
'uri': fields.Url('todo_ep')
}

task是一个字符串类型的字段,而uri是一个路由的endpoint参数,当然这些都不是死的,你也可以把uri改成uriii,这没有什么问题。如果这个endpoint不存在,即fields_Url(‘todo_ep’)中的值不存在,那么在运行Flask的时候会报错。如果你没有给路由设置endpoint,那么该路由的endpoint名称默认为该路由的视图名,也就是类名。你需要将其替换成你的视图名。下面来一段代码讲一下:

1
2
3
class Todo(Resource):
pass
api.add_resource(Todo, '/')

其中/的endpoint参数,即指向Todo视图的endpoint参数,其值为’todo’。
而如果你这么写的话:

1
2
3
class Todo(Resource):
pass
api.add_resource(Todo, '/', endpoint="fire")

那么你上面的fields.Url()的参数应该为’fire’,即fields.Url(‘fire’)。
当然,如果你认为麻烦,这个字段不写也是可以的,它其实就是一个路由的地址。
那么下面,我们首先定义一个类:

1
2
3
4
5
6
7
class TodoDao(object):
def __init__(self, todo_id, task):
self.todo_id = todo_id
self.task = task

# This field will not be send in the response
self.status = 'active'

这个类是用来接受参数的,不过实际响应的数据还是得看上面的定义的那个字典。

当然,一切还是以实践为主,所以下面我们贴上全部代码:

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
from flask import Flask, request
from flask_restful import Api, fields, marshal_with, Resource


app = Flask(__name__)
api = Api(app)

resource_fields = {
'todo_id': fields.String,
'task': fields.String,
}


class TodoDao(object):
def __init__(self, todo_id, task):
self.todo_id = todo_id
self.task = task

# This field will not be send in the response
self.status = 'active'


class Todo(Resource):
# 装饰器,传入前面的字典,这个字典规定了返回的内容
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task='Remeber the milk')


class ToBeBetter(Resource):
# 装饰器,传入前面的字典,这个字典规定了返回的内容
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task="Remeber Me.")
api.add_resource(Todo, '/')
api.add_resource(ToBeBetter, '/better')

if __name__ == '__main__':
app.run(debug=True)

那么接下来运行项目,然后请求接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 访问/
curl http://localhost:5000
{
"todo_id": "my_todo",
"task": "Remeber the milk"
}

# 访问/better
curl http://localhost:5000/better
{
"todo_id": "my_todo",
"task": "Remeber Me."
}

那么下面我加上uri参数:

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
from flask import Flask, request
from flask_restful import Api, fields, marshal_with, Resource


app = Flask(__name__)
api = Api(app)

resource_fields = {
'todo_id': fields.String,
'task': fields.String,
# 加上了uri参数
'uri': fields.Url('todo'),
}


class TodoDao(object):
def __init__(self, todo_id, task):
self.todo_id = todo_id
self.task = task

# This field will not be send in the response
self.status = 'active'


class Todo(Resource):
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task='Remeber the milk')


class ToBeBetter(Resource):
@marshal_with(resource_fields)
def get(self, **kwargs):
return TodoDao(todo_id='my_todo', task="Remeber Me.")
api.add_resource(Todo, '/')
api.add_resource(ToBeBetter, '/better')

if __name__ == '__main__':
app.run(debug=True)

然后使用curl访问接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 访问/
curl http://localhost:5000
{
"todo_id": "my_todo",
"task": "Remeber the milk",
"uri": "/"
}

# 访问/better
curl http://localhost:5000/better
{
"todo_id": "my_todo",
"task": "Remeber Me.",
"uri": "/"
}

相信这么一看大家就都明白了,那就是需要一个类来接受参数,需要一个字典来定义响应的参数,需要一个装饰器来完成根据字典的规范返回一个类。

评论



愿火焰指引你