现在单页 Web 项目很流行,使用各种 Js 框架,通过 Ajax 和服务器的 Api 进行交互,实现类似原生 app 效果,很酷,对 Flask 来说小菜一碟,是时候了解下 Flask-RESTful 了 开始前先了解下 RESTful,阮一峰老师有这样的解释:
也就是说 RESTful 一个框架和互联网应用的设计原则,遵循这个设计原则,可以让应用脱离前台展现的束缚,支持不同的前端设备。 安装Flask 的 RESTful 模块是 flask-restful ,使用 pip 安装: pip install flask-restful 如果安装顺利,可以在 Python Shell 环境下导入 >>> from flask_restful import Api >>> 小试牛刀安装好后,简单试试。flask-restful 像之前的 bootstrop-flask 以及 flask-sqlalchamy 模块一样,使用前需要对 Flask 应用进行初始化,然后会得到当前应用的 api 对象,用 api 对象进行资源绑定和路由设置: from flask import Flask from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app) # 初始化得到 api 对象 上面代码中从 flask_restful 中引入的 Resource 类是用来定义资源的,具体资源必须是 Resource 的子类,下面定义一个 HelloRESTful 资源: class HelloRESTful(Resource): def get(self): return {'greet': 'Hello Flask RESTful!'} 接着,给资源绑定 URI: api.add_resource(HelloRESTful, '/')
if __name__ == '__main__': # 别忘了启动应用的代码 app.run(debug=True) 在终端或者命令行下运行 访问 { "greet": "Hello Flask RESTful!" } 也可以用 curl 工具在终端或者命令行下发送请求: curl http://localhost:5000 -s { "greet": "Hello Flask RESTful!" }
资源从上面代码中可以看到,资源是 Resource 类的子类,以请求方法( GET、POST 等)名称的小写形式定义的方法,能对对应方法的请求作出相应,例如上面资源类中定义的 例如创建一个 todo 字样,支持获取代办事项和新增代办事项: # 初始化待办列表 todos = { 'todo_1': "读《程序员的自我修养》", 'todo_2': "买点吃的", 'todo_3': "去看星星" } class Todo(Resource): # 根据 todo_id 获取代办事项 def get(self, todo_id): return { todo_id: todos[todo_id] }
# 新增一个待办事项 def put(self, todo_id): todos[todo_id] = request.form['data'] return {todo_id: todos[todo_id]}
为 Todo 资源指定 URI: api.add_resource(Todo, '/todo/<string:todo_id>/') 启动项目,用 curl 工具测试: # 读取 key 为 todo_1 的待办事项 curl http://localhost:5000/todo/todo_1/ { "todo_1": "\u8bfb\u300a\u7a0b\u5e8f\u5458\u7684\u81ea\u6211\u4fee\u517b\u300b" }
# 创建一个 key 为 todo_4 的代办事项 curl http://localhost:5000/todo/todo_4/ -d "data=学习 Flask" -X PUT { "todo_4": "\u5b66\u4e60 Flask" }
# 读取刚添加的待办事项 todo_4 curl http://localhost:5000/todo/todo_4/ { "todo_4": "\u5b66\u4e60 Flask" } Flask-RESTful 支持多种视图方法的返回值: class Todo1(Resource): def get(self): # 直接返回 return { 'task': 'Hello world'}
class Todo2(Resource): def get(self): # 返回内容及状态码 return {'task': 'Hello world'}, 201
class Todo3(Resource): def get(self): # 返回内容,状态码以及 Header return {'task': 'Hello world'}, 200, {'Etag': 'some-opaque-string'} 为三个资源指定 URI: api.add_resource(Todo1, '/todo_1/') api.add_resource(Todo1, '/todo_2/') api.add_resource(Todo1, '/todo_3/') 启动项目后,用 curl 工具来测试: curl http://localhost:5000/todo_1/ { "task": "Hello world" }
# -请求 todo_2 并显示出 HTTP 标头,HTTP 状态码为 201 curl http://localhost:5000/todo_2/ -i HTTP/1.0 201 CREATED Content-Type: application/json Content-Length: 30 Server: Werkzeug/0.16.0 Python/3.7.5rc1 Date: Thu, 31 Oct 2019 14:12:54 GMT
{ "task": "Hello world" }
# -请求 todo_3 并显示出 HTTP 标头,HTTP 状态码为 200 ,标头中还有 Etag curl http://localhost:5000/todo_3/ -i HTTP/1.0 200 OK Content-Type: application/json Content-Length: 30 Etag: some-opaque-string Server: Werkzeug/0.16.0 Python/3.7.5rc1 Date: Thu, 31 Oct 2019 14:14:57 GMT
{ "task": "Hello world" }
路由从上面可以看到,通过 api.add_resource 方法来为资源设置路由 第一个参数是资源类,第二个参数是路由,和之前介绍的 可以为一个资源制定多个理由,例如: api.add_resource(Todo, '/todo/', '/mytodo/')
既然路由,就应该有 api.add_resource(Todo, '/todo/', endpoint='todo_ep') 设置路由的
请求解析RESTful 服务器对请求数据有很强的依赖,就请求数据的获取及校验是很繁琐的事情,还好 Flask-RESTful 提供了非常好的请求解析工具 from flask_restful import reqparse # 引入 reqparse 模块 # ...
parser = reqparse.RequestParser() # 定义全局的解析实体 # 定义参数 id,类型必须是整数 parser.add_argument('id', type=int, help='必须提供参数 id') # 定义参数 name,且为必填 parser.add_argument('name', required=True) # ...
class Reqparser(Resource): def get(self): args = parser.parse_args() # 获取解析器中定义的参数 并校验 return args
api.add_resource(Reqparser, '/reqparser/') # 指定路由 看下效果: # 提供一个非整数参数 id curl http://localhost:5000/reqparser/ -d "id=noint" -X GET { "message": { "id": "\u53c2\u6570 id \u5fc5\u987b\u662f\u6574\u6570" } }
# 不提供参数 name curl http://localhost:5000/reqparser/ { "message": { "name": "Missing required parameter in the JSON body or the post body or the query string" } }
请求解析器支持继承,可以定义最高级别的解析器,逐渐细化,最后应用的具体资源上: from flask_restful import reqparse
parser = reqparse.RequestParser() parser.add_argument('foo', type=int)
parser_copy = parser.copy() # 继承 parser_copy.add_argument('bar', type=int) # parser_copy 将有两个参数
# 改变继承来的参数 foo 必填且的获取位置为 querystring parser_copy.replace_argument('foo', required=True, location='args')
# 删除继承来的参数 foo parser_copy.remove_argument('foo') 格式化输出请求解析处理用收到的信息,对于输入的信息也可以处理,通过 Flask-RESTful 提供的类 fields 和注解 marshal_with 来实现: from flask_restful import Resource, fields, marshal_with
resource_fields = { 'name': fields.String, 'address': fields.String, 'date_updated': fields.DateTime(dt_format='rfc822'), }
class TodoFormat(Resource): @marshal_with(resource_fields, envelope='resource') def get(self): return db_get_todo() # 某个获得待办事项的方法
格式化模板属性名,需要在响应函数返回的对象属性中匹配,如果需要会要对字段重命名,可以这样: fields = { # name 将被重命名为 private_name 'name': fields.String(attribute='private_name'), 'address': fields.String } 返回值中没有可以定义默认值: fields = { # 为 name 设置默认值 'name': fields.String(default='Anonymous User'), 'address': fields.String } 总结本节课程简单介绍了 Flask 如何玩 RESTful,通过对 RESTful 的说明,讲解了 Flask-RESTful 模块的用法,并简单讲解了资源、路由,以及请求解析和格式化输出等技术
参考
系列文章 第0-40天:从0学习Python 0-40合集 |
|