当前位置:   article > 正文

34. Flask 集成 flask-restful

todos = [] flask

需求

一般 Flask 框架默认写 api 的请求就是写一个函数视图,如下:

  1. @app.route('/add_list', methods=["POST"])
  2. def add_list():
  3. ...
  4. @app.route('/get_list', methods=["GET"])
  5. def get_list():
  6. ...

这种方式当然可以开发 api, 但是当我们想要基于 restful 风格来编写 api,就不太方便了。就需要写 4 个单独的函数视图,如下:

  1. # result api
  2. # 路由 /list
  3. # 增 POST
  4. # 删 DELETE
  5. # 查 GET
  6. # 改 PUT
  7. # 具体函数方法如下:就要写4个分开的函数,这样就感觉一种不太好的感觉。
  8. @app.route('/list', methods=["POST"])
  9. def add_list():
  10. ...
  11. @app.route('/list', methods=["GET"])
  12. def get_list():
  13. ...
  14. @app.route('/list', methods=["DELETE"])
  15. def delete_list():
  16. ...
  17. @app.route('/list', methods=["PUT"])
  18. def save_list():
  19. ...

有没有一种更加简洁的方法呢? 例如:

  1. class List(restful.Resource):
  2. # get 查询
  3. def get(self):
  4. # post 新增
  5. def post(self):
  6. # delete 删除
  7. def delete(self):
  8. # put 修改
  9. def put(self):

其实也就是跟 Django 的类视图一样的开发方式了,下面我们就要介绍一下使用 flask-resutful 库来完成这个需求。

参考文档

http://www.pythondoc.com/flask-restful/first.html

https://flask-restful.readthedocs.io/en/latest/

安装 Flask-Restful

使用 pip 安装:

$ pip install flask-restful

快速入门示例

1. 一个很小的 Flask-RESTful API 示例

  1. from flask import Flask
  2. from flask_restful import Resource, Api # 导入flask_resutful
  3. app = Flask(__name__)
  4. api = Api(app) # 创建 api
  5. # 编写api的请求业务: api资源
  6. class HelloWorld(Resource):
  7. # get请求
  8. def get(self):
  9. return {'hello': 'world'} # 简化了json格式返回,等价于 return jsonify({'hello': 'world'})
  10. # 设置api的url路径:api 路径
  11. api.add_resource(HelloWorld, '/')
  12. if __name__ == '__main__':
  13. app.run(debug=True)

启动服务:

  1. $ python api.py
  2. * Running on http://127.0.0.1:5000/
  3. * Restarting with reloader

测试如下:

image-20200918170222913

2. 配置资源的路由 Resourceful Routing

上面我们已经写了一个最简单的 flask-restful api 示例,下面来增加多 put 请求,并且统一可以配置 资源的路由 Resourceful Routing, 示例如下:

  1. from flask import Flask, request
  2. from flask_restful import Resource, Api # 导入flask_resutful
  3. app = Flask(__name__)
  4. api = Api(app) # 创建 api
  5. # 创建todos
  6. todos = {}
  7. # 编写Api资源
  8. class TodoSimple(Resource):
  9. # get请求
  10. def get(self, todo_id):
  11. return {todo_id: todos[todo_id]}
  12. # put请求
  13. def put(self, todo_id):
  14. todos[todo_id] = request.form['data']
  15. return {todo_id: todos[todo_id]}
  16. # 配置资源的路由
  17. api.add_resource(TodoSimple, '/<string:todo_id>')
  18. if __name__ == '__main__':
  19. app.run(debug=True, host="0.0.0.0", port="5000")

可以看到,我们写了两个请求 get 和 put,两个请求都是同一个 url 路径,下面使用 curl 测试如下:

  1. # 执行put请求,设置 todo1
  2. [root@dev ~]# curl http://10.120.10.241:5000/todo1 -d "data=Remember the milk" -X PUT
  3. {
  4. "todo1": "Remember the milk"
  5. }
  6. [root@dev ~]#
  7. # 执行get请求,查询 todo1
  8. [root@dev ~]# curl http://10.120.10.241:5000/todo1 -X GET
  9. {
  10. "todo1": "Remember the milk"
  11. }
  12. [root@dev ~]#
  13. # 执行put请求,设置 todo2
  14. [root@dev ~]# curl http://10.120.10.241:5000/todo2 -d "data=Change my brakepads" -X PUT
  15. {
  16. "todo2": "Change my brakepads"
  17. }
  18. [root@dev ~]#
  19. # 执行get请求,查询 todo2
  20. [root@dev ~]# curl http://10.120.10.241:5000/todo2 -X GET
  21. {
  22. "todo2": "Change my brakepads"
  23. }
  24. [root@dev ~]#

3.设置返回响应的 响应体、 响应码 以及 响应头

与 Flask 的返回响应一致, Flask Restful 设置的返回也是按照如下格式设置响应的:

return 响应体, 状态码, 响应头

下面只要再写一个API即可示例:

  1. # 设置响应信息示例
  2. class ReponseInfo(Resource):
  3. def get(self):
  4. # 响应体, 状态码, 响应头
  5. return {'task': 'Hello world'}, 201, {'Etag': 'some-opaque-string', 'city': 'shenzhen'}
  6. api.add_resource(ReponseInfo, '/res')

启动服务之后,使用 curl 测试如下:

  1. [root@dev ~]# curl -i http://10.120.10.241:5000/res -X GET
  2. HTTP/1.0 201 CREATED # http响应码 201
  3. Content-Type: application/json
  4. Content-Length: 30
  5. Etag: some-opaque-string # 自定义的响应 header
  6. city: shenzhen # 自定义的响应 header
  7. Server: Werkzeug/0.16.0 Python/3.7.2
  8. Date: Fri, 18 Sep 2020 09:23:04 GMT
  9. # 返回的响应体
  10. {
  11. "task": "Hello world"
  12. }
  13. [root@dev ~]#

4. 设置API的路径,也就是资源的端点 Endpoints

4.1 配置多个URL至同一个Api资源

有些使用对于一个Api资源可能会有多个 url 路径进行访问,例如:访问首页可能使用 / 或者 /index 都可以访问,那么这个 Api 的端点可以配置示例如下:

  1. # 设置首页
  2. class Index(Resource):
  3. def get(self):
  4. return {'msg': 'index'}
  5. # 配置多个url路径到访问首页
  6. api.add_resource(Index, '/', '/index')

启动服务之后,使用 curl 测试两个路径如下:

  1. [root@dev ~]# curl -i http://10.120.10.241:5000/ -X GET
  2. HTTP/1.0 200 OK
  3. Content-Type: application/json
  4. Content-Length: 23
  5. Server: Werkzeug/0.16.0 Python/3.7.2
  6. Date: Fri, 18 Sep 2020 09:36:02 GMT
  7. {
  8. "msg": "index"
  9. }
  10. [root@dev ~]#
  11. [root@dev ~]# curl -i http://10.120.10.241:5000/index -X GET
  12. HTTP/1.0 200 OK
  13. Content-Type: application/json
  14. Content-Length: 23
  15. Server: Werkzeug/0.16.0 Python/3.7.2
  16. Date: Fri, 18 Sep 2020 09:36:06 GMT
  17. {
  18. "msg": "index"
  19. }
  20. [root@dev ~]#

可以看到两个URL的路径都能够正常访问 index

4.2 设置 url 的命名端点 endpoint

跟Django的命名路由 url 一样,我们也可以使用参数给 endpoint 进行命名,然后使用 flask-restful 库中的 url_for() 来解析 url 路径,示例代码如下:

  1. from flask_restful import url_for # 导入flask_resutful的url,注意不是 flask 的 url_for
  2. # 设置首页
  3. class Index(Resource):
  4. def get(self):
  5. return {
  6. 'msg': 'index',
  7. 'url': url_for('index') # 使用url_for解析出命名为 index 的路径,如果有多个路径,则返回第一个
  8. }
  9. # 配置多个url路径到访问首页
  10. api.add_resource(Index, '/', '/index', endpoint='index')

启动服务,使用 curl 测试如下:

  1. [root@dev ~]# curl -i http://10.120.10.241:5000/index -X GET
  2. HTTP/1.0 200 OK
  3. Content-Type: application/json
  4. Content-Length: 39
  5. Server: Werkzeug/0.16.0 Python/3.7.2
  6. Date: Fri, 18 Sep 2020 10:57:54 GMT
  7. {
  8. "msg": "index",
  9. "url": "/" # 就算请求的是 /index 路径,但是 url_for 返回的还是第一个 / 路径
  10. }
  11. [root@dev ~]#

5. 设置认证修饰器

之前我们使用函数写视图方法的时候,是比较方便写一些修饰器的,那么如果我们需要给 类视图资源 设置修饰器,该怎么办呢?

下面我们使用 HTTP 的 BasicAuth 来写一个登陆的修饰器使用。

5.1. 安装BasicAuth需要的库
pip install Flask-HTTPAuth
5.2 导入BasicAuth的相关库
  1. from flask_httpauth import HTTPBasicAuth
  2. from werkzeug.security import generate_password_hash, check_password_hash
5.3 视图函数使用认证如下
  1. from flask import Flask, request, make_response, jsonify
  2. from flask_restful import Resource, Api, url_for # 导入flask_resutful
  3. from flask_httpauth import HTTPBasicAuth
  4. from werkzeug.security import generate_password_hash, check_password_hash
  5. app = Flask(__name__)
  6. api = Api(app) # 创建 api
  7. auth = HTTPBasicAuth() # 创建BasicAuth对象
  8. # 用户的名称以及密码
  9. users = {
  10. "john": generate_password_hash("hello"),
  11. "susan": generate_password_hash("bye")
  12. }
  13. # 验证用户密码的修饰器
  14. @auth.verify_password
  15. def verify_password(username, password):
  16. if username in users and check_password_hash(users.get(username), password):
  17. return username
  18. # 自定义未认证通过的返回
  19. @auth.error_handler
  20. def unauthorized():
  21. return make_response(jsonify({'error': 'Unauthorized access'}), 401)
  22. # 设置首页
  23. class Index(Resource):
  24. # 设置登陆的修饰器
  25. decorators = [auth.login_required]
  26. def get(self):
  27. return {
  28. 'msg': 'index',
  29. 'url': url_for('index') # 使用url_for解析出命名为 index 的路径,如果有多个路径,则返回第一个
  30. }
  31. # 配置多个url路径到访问首页
  32. api.add_resource(Index, '/', '/index', endpoint='index')
  33. if __name__ == '__main__':
  34. app.run(debug=True, host="0.0.0.0", port="5000")

启动服务之后,下面我们使用 curl 来测试一下:

  1. # 没有设置用户名、密码,则返回认证失败
  2. [root@dev ~]# curl -i http://10.120.10.241:5000/
  3. HTTP/1.0 401 UNAUTHORIZED
  4. Content-Type: application/json
  5. Content-Length: 37
  6. WWW-Authenticate: Basic realm="Authentication Required"
  7. Server: Werkzeug/0.16.0 Python/3.7.2
  8. Date: Mon, 21 Sep 2020 03:03:09 GMT
  9. {
  10. "error": "Unauthorized access"
  11. }
  12. [root@dev ~]#
  13. # 设置用户名、密码,成功访问
  14. [root@dev ~]# curl -u john:hello -i http://10.120.10.241:5000/
  15. HTTP/1.0 200 OK
  16. Content-Type: application/json
  17. Content-Length: 39
  18. Server: Werkzeug/0.16.0 Python/3.7.2
  19. Date: Mon, 21 Sep 2020 03:04:02 GMT
  20. {
  21. "msg": "index",
  22. "url": "/"
  23. }
  24. [root@dev ~]#

6.设置多个自定义修饰器

上面我们已经成功使用上的 BasicAuth修饰器, 我们再自定义一个简单的修饰器,添加到 资源视图类 中。

6.1 编写一个自定义修饰器
  1. import functools
  2. # 自定义的装饰器
  3. def test_required(view_func):
  4. # wraps函数的作用是将wrapper内层函数的属性设置为被装饰函数view_func的属性
  5. @functools.wraps(view_func)
  6. def wrapper(*args, **kwargs):
  7. print("=====执行自定义装饰器==========")
  8. return view_func(*args, **kwargs)
  9. return wrapper
6.2 在资源视图类添加使用修饰器 test_required
image-20200921111919339
  1. from flask import Flask, request, make_response, jsonify
  2. from flask_restful import Resource, Api, url_for # 导入flask_resutful
  3. from flask_httpauth import HTTPBasicAuth
  4. from werkzeug.security import generate_password_hash, check_password_hash
  5. import functools
  6. app = Flask(__name__)
  7. api = Api(app) # 创建 api
  8. auth = HTTPBasicAuth() # 创建BasicAuth对象
  9. # 用户的名称以及密码
  10. users = {
  11. "john": generate_password_hash("hello"),
  12. "susan": generate_password_hash("bye")
  13. }
  14. # 验证用户密码的修饰器
  15. @auth.verify_password
  16. def verify_password(username, password):
  17. if username in users and check_password_hash(users.get(username), password):
  18. return username
  19. # 自定义未认证通过的返回
  20. @auth.error_handler
  21. def unauthorized():
  22. return make_response(jsonify({'error': 'Unauthorized access'}), 401)
  23. # 自定义的装饰器
  24. def test_required(view_func):
  25. # wraps函数的作用是将wrapper内层函数的属性设置为被装饰函数view_func的属性
  26. @functools.wraps(view_func)
  27. def wrapper(*args, **kwargs):
  28. print("=====执行自定义装饰器==========")
  29. return view_func(*args, **kwargs)
  30. return wrapper
  31. # 设置首页
  32. class Index(Resource):
  33. # 设置登陆的修饰器\自定义修饰器
  34. decorators = [auth.login_required, test_required]
  35. def get(self):
  36. return {
  37. 'msg': 'index',
  38. 'url': url_for('index') # 使用url_for解析出命名为 index 的路径,如果有多个路径,则返回第一个
  39. }
  40. # 配置多个url路径到访问首页
  41. api.add_resource(Index, '/', '/index', endpoint='index')
  42. if __name__ == '__main__':
  43. app.run(debug=True, host="0.0.0.0", port="5000")

启动服务之后,使用 curl 测试如下:

  1. [root@dev ~]# curl -u john:hello -i http://10.120.10.241:5000/
  2. HTTP/1.0 200 OK
  3. Content-Type: application/json
  4. Content-Length: 39
  5. Server: Werkzeug/0.16.0 Python/3.7.2
  6. Date: Mon, 21 Sep 2020 03:17:21 GMT
  7. {
  8. "msg": "index",
  9. "url": "/"
  10. }
  11. [root@dev ~]#

同时后台打印 自定义修饰器的 信息:

image-20200921112054807

验证集成 Flask-Restful 处理 GET POST 的请求参数

上面我们已经基本了解集成 Flask-Restful 的使用了,那么集成了之后,对于GET请求的query参数获取、POST请求的表单或者json参数获取,有什么地方要注意的么?下面我们来写一个演示实例。

1.示例代码

  1. from flask import Flask, request
  2. from flask_restful import Resource, Api, url_for # 导入flask_resutful
  3. import json
  4. # 设置集成Flask-Resutful的POST请求
  5. class Requests(Resource):
  6. def get(self):
  7. """接收处理query参数: ?user_name=libai&user_age=17"""
  8. # 接收处理GET数据请求
  9. user_name = request.args.get('user_name')
  10. user_age = request.args.get('user_age')
  11. return {"user_name": user_name, "user_age": user_age}
  12. def post(self):
  13. """接收处理json数据请求"""
  14. data = json.loads(request.data) # 将json字符串转为dict
  15. user_name = data['user_name']
  16. user_age = data['user_age']
  17. return {"user_name": user_name, "user_age": user_age}
  18. api.add_resource(Requests, '/requests', endpoint='request')
  19. if __name__ == '__main__':
  20. app.run(debug=True, host="0.0.0.0", port="5000")

2.使用 postman 测试 GET 请求,获取 query 参数的情况

image-20200921134816181

可以看到正常获取参数。

3.使用 postman 测试 POST 请求,获取 json 请求体参数的情况

image-20200921134908807

也是能够正常获取参数。

4.总结:

获取 query 参数 或者 json请求体参数,都是从 flask 库的 request 中获取,集成 Flask-Restful 并不影响使用。

from flask import request

验证集成 Flask-Restful 以及 蓝图 BluePrint

使用了 Flask-Restful 后,定义路由的方式就不同了一些,那么会不会影响蓝图的使用呢? 下面来写个示例看看。

注意:在蓝图中,如果使用Flask_RESTful,那么在创建Api对象的时候,使用蓝图对象,不再是使用app对象了.

1.创建一个 admin 的蓝图应用

  1. from flask_restful import Resource, Api # 导入flask_resutful
  2. from flask import Blueprint
  3. #Blueprint必须指定两个参数,admin表示蓝图的名称,__name__表示蓝图所在模块
  4. admin = Blueprint('admin',__name__)
  5. api = Api(admin) # 注意: 使用蓝图对象来创建 api
  6. # API业务
  7. class AdminView(Resource):
  8. def get(self):
  9. return {"msg": "admin index"}
  10. # 配置url路径
  11. api.add_resource(AdminView, '/', endpoint='admin')

可以从代码看到,本来 flask_restful 的 Api 创建是需要 flask 的 app 的,这里就采用 蓝图对象 而已,其他使用上没有什么区别。

2.创建 app,注册蓝图应用

  1. from flask import Flask
  2. # 创建app
  3. app = Flask(__name__)
  4. # 注册蓝图
  5. from .admin import admin
  6. app.register_blueprint(admin,url_prefix='/admin')
  7. if __name__ == '__main__':
  8. app.run(debug=True, host="0.0.0.0", port="5000")

3. 使用postman测试如下

image-20200921142249599
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/604708
推荐阅读
相关标签
  

闽ICP备14008679号