Jusene's Blog

Flask框架之RESTful Api

字数统计: 879阅读时长: 4 min
2018/01/03 Share

REST

REST是所有Web应用都应该遵守的架构设计指导原则,Representational State Transfer(表现层状态转化),面向资源是REST最明显的特征,对于同一资源的一组不同的操作,资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST要求,必须通过统一接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。

安装和使用

1
pip install flask-restful
1
from flask import Flask
2
from flask.ext import restful
3
4
app=Flask(__name__)
5
api=restful.Api(app)
6
7
class HelloFlask(restful.Resource):
8
    def get(self):
9
        return {'hello':'flask'}
10
11
api.add_resource(HelloFlask,'/')
12
13
if __name__ == "__main__":
14
    app.run(debug=True)

Flask-RESTful提供的最主要的基础就是resources,只要在你的资源上定义方法就能容易地访问多个HTTP方法。

1
from flask import Flask,request
2
from flask.ext.restful import Resource,Api
3
4
app=Flask(__name__)
5
api=Api(app)
6
7
todos={}
8
9
class TodoSimple(Resource):
10
    def get(self,todo_id):
11
        return {todo_id:todos[todo_id]}
12
    def put(self,todo_id):
13
        todos[todo_id]=request.form['data']
14
        return {todo_id:todos[todo_id]}
15
16
api.add_resource(TodoSimple,'/<string:todo_id>')
17
18
if __name__ == "__main__":
19
    app.run(debug=True)
1
~]# curl -XPUT http://127.0.0.1:5000/todo1 -d "data=Chagne Me"
2
{
3
    "todo1": "Change Me"
4
}
5
~]# curl http://127.0.0.1:5000/todo1
6
{
7
    "todo1": "Change Me"
8
}
1
>>> from requests import put,get
2
>>> put('http://127.0.0.1:5000/todo2',data={'data':"Remember Me"}).json()
3
{'todo2': 'Remember Me'}
4
>>> get('http://127.0.0.1:5000/todo2').json()
5
{'todo2': 'Remember Me'}

Flask-RESTful支持视图方法多种类型返回值,它将会被转换成一个包含原始 Flask 响应对象的响应,Flask-RESTful 也支持使用多个返回值来设置响应代码和响应头。

1
from flask import Flask
2
from flask.ext.restful import Resource,Api
3
4
app=Flask(__name__)
5
api=Api(app)
6
7
class Default(Resource):
8
    def get(self):
9
        return {'message':'OK'}
10
class Error(Resource):
11
    def get(self):
12
        return {'error':'fail'},404
13
class Header(Resource):
14
    def get(self):
15
        return {'api':'Restful'},201,{'Server':'Api Server'}
16
17
api.add_resource(Default,'/')
18
api.add_resource(Error,'/error')
19
api.add_resource(Header,'/header')
20
21
if __name__ == "__main__":
22
    app.run(debug=True)

参数解析

Flask能够简单地访问请求数据(比如查询字符串或者POST表单编码的数据),验证表单数据仍然很痛苦,Flask-RESTful内置了支持验证请求数据,它使用了一个类似argparse的库。

1
from flask import Flask,request
2
from flask.ext.restful import Resource,Api,reqparse
3
4
app=Flask(__name__)
5
api=Api(app)
6
7
8
class Default(Resource):
9
    def get(self,arg):
10
        return {arg:bands[arg]}
11
    def put(self,arg):
12
        parser=reqparse.RequestParser()
13
        parser.add_argument('rate',type=int,help='Rate must int')
14
        args=parser.parse_args()
15
        return args
16
api.add_resource(Default,'/<string:arg>')
17
18
if __name__ == "__main__":
19
    app.run(debug=True)
1
~]# curl -XPUT -d 'rate=foo' 127.0.0.1:5000/rate
2
{
3
    "message": {
4
        "rate": "rate must int"
5
    }
6
}
7
~]# curl -XPUT -d 'rate=1000' 127.0.0.1:5000/rate
8
{
9
    "rate": "1000"
10
}

完整例子:

1
from flask import Flask
2
from flask.ext.restful import reqparse,abort,Api,Resource
3
4
app=Flask(__name__)
5
api=Api(app)
6
7
TODOS={
8
    'todo1':{'task':'build an API'},
9
    'todo2':{'task':'????'},
10
    'todo3':{'task':'profit!'},
11
}
12
13
def abort_if_todo_doesnt_exist(todo_id):
14
    if todo_id not in TODOS:
15
        abort(404,message="Todo {} doesn't exist".format(todo_id))
16
17
parser=reqparse.RequestParser()
18
parser.add_argument('task',type=str)
19
20
class Todo(Resource):
21
    def get(self,todo_id):
22
        abort_if_todo_doesnt_exist(todo_id)
23
        return TODOS[todo_id]
24
    def delete(self,todo_id):
25
        abort_if_todo_doesnt_exist(todo_id)
26
        del TODOS[todo_id]
27
        return '',204
28
    def put(self,todo_id):
29
        args=parser.parse_args()
30
        task={'task':args['task']}
31
        TODOS[todo_id]=task
32
        return task,201
33
class TodoList(Resource):
34
    def get(self):
35
        return TODOS
36
    
37
    def post(self):
38
        args=parser.parse_args()
39
        todo_id=int(max(TODOS.keys()).lstrip('todo'))+1
40
        todo_id='todo%i' % todo_id 
41
        TODOS[todo_id]={'task':args['task']}
42
        return TODOS[todo_id],201
43
44
api.add_resource(TodoList,'/todos')
45
api.add_resource(Todo,'/todos/<todo_id>')
46
47
if __name__ == "__main__":
48
    app.run()
CATALOG
  1. 1. REST
  2. 2. 安装和使用
  3. 3. 参数解析