Flask-RESTPlus
2020-03-11 本文已影响0人
睡不醒的大橘
RESTful
RESTful 特点
- REST即Representational State Transfer的缩写。REST最大的几个特点为:资源、统一接口、URI和无状态。
- 资源:网络上的一个实体或具体信息。JSON是现在最常用的资源表示格式。
- 统一接口:数据的元操作,即CRUD操作,分别对应于HTTP方法:
- GET用来获取资源
- POST用来新建资源(也可用于更新资源)
- PUT用来更新资源
- DELETE用来删除资源。
- URI:URI是每一个资源的地址或识别符。最典型的URI即URL。
- 无状态:所有的资源,都可以通过URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变。
RESTful 编写规范
Response数据和状态码(status code)
Flask-RESTPlus
(一)快速入门
-
Flask-RESTPlus是对Flask的扩展,它增加了对快速开发REST API的支持。Flask-RESTPlus中提供了大量的装饰器和工具来描述你的API,并以文档化的形式将这些接口展现出来(通过Swagger来实现)。
-
安装
pip install flask-restplus
路由(Routing)
from flask import Flask, request
from flask_restplus import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
@api.route('/<string:todo_id>')
class TodoSimple(Resource):
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]}
if __name__ == '__main__':
app.run()
- 通过传入Flask实例进行初始化
- Flask-RESTPlus提供的主要创建对象就是资源(Resource)。资源创建于Flask,可插入视图(pluggable view)之上,使得我们可以通过在资源上定义方法来很容易地访问多个HTTP方法。
- 在浏览器中直接访问我们API的根路径,即http://127.0.0.1:5000,此时会显示Swagger的界面,里面包含了我们的Restful API的相应信息。
- 可以从 python shell 中运行:
>>> from requests import put, get
>>> put('http://localhost:5000/todo1', data={'data': 'Remember the milk'}).json()
{'todo1': 'Remember the milk'}
>>> get('http://localhost:5000/todo1').json()
{'todo1': 'Remember the milk'}
>>> put('http://localhost:5000/todo2', data={'data': 'Change my brakepads'}).json()
{'todo2': 'Change my brakepads'}
>>> get('http://localhost:5000/todo2').json()
{'todo2': 'Change my brakepads'}
- Flask-RESTPlus理解视图方法中的多种类型的返回值。类似于Flask,你可以返回任何可迭代的类型,它会将该返回值转换成响应对象(response)。Flask-RESTPlus还提供了设置响应码和响应头的功能:
class Todo1(Resource):
def get(self):
# 默认为200 OK
return {'task': 'Hello world'}
class Todo2(Resource):
def get(self):
# 设置响应码为201
return {'task': 'Hello world'}, 201
class Todo3(Resource):
def get(self):
# 设置响应码为201,并返回自定义的响应头
return {'task': 'Hello world'}, 201, {'Etag': 'some-opaque-string'}
端点 (Endpoints)
- 我们可以向Api对象的add_resource()方法或route()装饰器中传入多个URL,这样每个URL都将会路由到该资源上
api.add_resource(TodoSimple, '/simple1', '/simple2')
# 或者下面装饰器方式,二者等价
@api.route('/simple1', '/simple2')
class TodoSimple(Resource):
pass
- 如果一个请求(request)与应用的任何端点都不匹配,那么Flask-RESTPlus将会返回一个404错误信息,并给出其他与所请求端点最匹配的建议信息。
命名空间 (Namespace)
- 作用是为不同的资源,不同的url分组
from flask_restplus import Namespace
ns = Namespace('node', description='node operations', path='/root')
api.add_namespace(ns)
@ns.route('/simple')
class TodoSimple(Resource):
def get(self, todo_id):
return {'simple1': 'simple2'}
(二)请求解析(Argument Parsing)
- Flask-RESTPlus内置支持对请求数据的验证,这一功能是通过使用一个类似于argparse的库来实现的:
from flask import Flask
from flask_restplus import Resource, Api, reqparse
app = Flask(__name__)
api = Api(app)
todos = {}
parser = reqparse.RequestParser()
parser.add_argument('data', type=int, required=True, help='data cannot be converted.')
parser.add_argument('name', type=str)
@api.route('/<string:todo_id>')
class TodoSimple(Resource):
def put(self, todo_id):
args = parser.parse_args()
todos[todo_id] = args['data']
return {todo_id: todos[todo_id]}
if __name__ == '__main__':
app.run()
- parse_args()返回的是一个Python字典
- 如果一个参数未验证通过,Flask-RESTPlus将响应一个400 Bad Request。如果你指定了 help 参数的值,在解析的时候当类型错误被触发的时候,它将会被作为错误信息给呈现出来。如果你没有指定 help 信息的话,默认行为是返回类型错误本身的信息。
- 在默认情况下,参数不是必需的。而且,在请求中提供的参数不属于 RequestParser 的一部分的话将会被忽略。可以在调用parse_args时传入strict=True,以确保在请求中包含解析器没有定义的参数时抛出错误。
>>> put('http://localhost:5000/todo1', data={'data': '1'}).json()
{'todo1': 1}
>>> put('http://localhost:5000/todo1', data={}).json()
{'errors': {'data': 'Missing required parameter in the JSON body or the post body or the query string'}, 'message': 'Input payload validation failed'}
>>> put('http://localhost:5000/todo1', data={'data': 'a'}).json()
{'errors': {'data': "data cannot be converted. invalid literal for int() with base 10: 'a'"}, 'message': 'Input payload validation failed'}
参数位置
- 默认下,RequestParser 试着从 flask.Request.values,以及 flask.Request.json 解析值。
- 在 add_argument() 中使用 location 参数可以指定解析参数的位置。flask.Request 中任何变量都能被使用。例如:
# 仅在 POST body中查找
parser.add_argument("method", location="form")
# 仅在querystring中查找
parser.add_argument("PageSize", location="args")
# 从请求头中查找
parser.add_argument("User-Agent", location="headers")
# 从http cookies中查找
parser.add_argument("session_id", location="cookies")
# 从上传文件中查找
parser.add_argument("picture", type=werkzeug.datastructures.FileStorage, location="files")
# 内部调用get_json(),可通过字典的方式获取键值,如果没有对应的键,那么会返回HTTP 400错误响应
parser.add_argument("name", location="json")
@api.expect()
- @api.expect()装饰器允许你指定request body中期望的field,可以通过validate指定是否需要对其进行验证。
from flask import Flask
from flask_restplus import Resource, Api, reqparse, fields
app = Flask(__name__)
api = Api(app)
todos = {}
model = api.model('model', {
'data': fields.Integer,
})
@api.route('/<string:todo_id>')
class TodoSimple(Resource):
@api.expect(model, validate='True')
def put(self, todo_id):
pass
if __name__ == '__main__':
app.run()
自定义验证
- 对于解析参数,可以执行自定义验证, 然后你可以在RequestParser 中使用这些自定义的输入类型:
def odd_number(value):
if value % 2 == 0:
raise ValueError("Value is not odd")
return value
parser = reqparse.RequestParser()
parser.add_argument('data', type=odd_number, required=True, location='json')