上篇文章主要介绍了 flask-restplus 构建 rest api 的主要用法,这篇文章将介绍如何使用此扩展构建 文档 , 实现 文档跟着代码走 .
上一篇文章已经提到, 文档默认是开启的,而且默认挂载到 / 根路由, 在使用 api = Api(app) 的时候, 会有个默认参数 doc='/' , 这里的 doc 是指定文档地址挂载点的, 还有个参数为 version , 它的值默认为 1.0 , 表示当前文档的版本, 使用 title 参数可以描述文档标题. 示例代码如下所示:
from flask import Flask
from flask_restplus import Api, Resource
app = Flask(__name__)
api = Api(app, doc='/doc', version='1.0', title='学习 Flask-RESTPlus')
@api.route('/hello')
class HelloWorld(Resource):
def get(self):
return {'hello': 'world'}
复制代码
此时 doc 参数设置为 /doc , 那访问 /doc 就可以访问到文档:
如上所示,文档的标题为 学习 Flask-RESTPlus , 版本为 1.0 , 并且默认渲染资源路由. 有一点需要注意, 如果是使用 Flask 实例 初始化的 Api 对象, 那么文档的 base_url 为 / , 但是如果是使用 蓝图 初始化, 并且在初始化蓝图对象时设置了 url_prefix 参数, 那么文档的 base_url 是挂载到蓝图的 url_prefix 上的. 以下代码表示将文档挂载到蓝图根路由, 即 /api/v1 .
api_v1 = Blueprint('api_v1', __name__, url_prefix='/api/v1')
api = Api(api_v1, version='1.0', title='API')
复制代码
上一小节中的文档渲染出来为默认的命名空间, 一个命名空间对应一个资源, 它的文档也将列在其命名空间下, 以下为示例:
from flask_restplus import Api, Namespace, Resource
app = Flask(__name__)
api = Api(app, doc='/', version='1.0', title='待办列表API')
todos = Namespace('todos', description='待办列表')
practice = Namespace('practice', description='练习')
api.add_namespace(todos)
api.add_namespace(practice)
@todos.route('')
class TODOList(Resource):
def get(self):
return []
@practice.route('')
class Practice(Resource):
def get(self):
return []
复制代码
渲染出的文档结果如下所示, 可以看到渲染出的文档一目了然:
使用 flask-restplus 提供的 fileds 模型, 将它与 ORM 对象或者自定义类对应,可以很方便渲染响应和请求参数. 其实它是类似于将对象进行序列化的工具, 在请求的时候, 通过模型判断请求参数, 在响应的时候通过模型进行序列化. 同时文档也可以通过模型来渲染需要的请求参数以及响应数据结构.
model = api.model('Model', {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
})
复制代码
以上创建了一个名为 Model 拥有三个字段的模型, 创建完成后可以使用 api.expect(model) 来渲染请求参数文档, 使用 api.response(mode=model) 来渲染响应数据文档, 这个我们接下来讲.
flask-restplus 提供的 api.expect 用来渲染请求参数, todos.response 用来渲染响应数据,有多个响应, 就可以多次使用此装饰器, 以下代码渲染出的文档效果如下:
@todos.route('')
class TODOList(Resource):
@todos.expect(model)
@todos.response(code=200, model=model, description='请求成功响应')
def get(self):
return []
复制代码
如图所示, model 模型已经被自动转化为 json 格式的数据. 同时渲染出的 Swagger 文档还提供了发送请求功能, 也就是右上角的 Try it out . 如果想要响应模型列表, 可以这样写 todos.response(code=200, model=[model], description='请求成功响应') , 如果我只需要模型中的部分字段只用于响应, 另一部分字段只用于请求,这就需要使用到 字段属性 了.
模型提供了很多直接对应 Python 数据类型的字段, 以下为部分常用字段:
fields.Integer 表示数字 fields.String 表示字符串 fields.Datetime 表示日期 fields.List 表示列表
fields.List(fields.String) 将列表项字段传入其中即可 etc 除了这些常规字段,如果一个字段对应的值是另一个模型, 类似与数据库 一对一 或者 一对多 的关系, 可以使用 fields.Nested 字段. 使用方式如下:
model = api.model('Model', {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
})
# 直接引用一个模型
another_model = api.model('AnotherModel', {
'model': fields.Nested(model)
})
# 引用模型列表
another_model = api.model('AnotherModel', {
'model': fields.List(fields.Nested(model))
})
# 或者
another_model = api.model('AnotherModel', {
'model': fields.Nested(model, as_list=True)
})
复制代码
还有一些其他字段以及高阶用法, 可以参考 文档
类似于 fields.String 或者 fields.Integer 的字段都拥有自己的属性, 如果使用过 SQLalchemy 的话, 它与模型类的字段属性是同一个性质, 可以对属性赋值, 来更加细致的描述当前属性:
required 用来设置是否为必传参数, 默认为 False readonly 用来设置只读, 表示只有在响应的时候才会出现, 默认为 None example 用力设置示例, 默认为 None description 属性用来描述当前字段信息, 默认为 None 部分字段属性同时也提供了参数校验功能, 对于 fields.String :
enum min_length max_length pattern
对于 fields.Integer fields.Float :
min 最小值 max 最大值 exclusiveMin : 如果为 True , 则左开区间, 默认为 False exclusiveMax : 如果为 True , 则右开区间, 默认为 False multiple : 值必须是这个数的倍数 使用 @todos.expect(model, validate=True) 就可以开启参数验证, 参数验证出错会抛出 400 异常.
parser 进行参数验证 如上所述, 模型是以 json 的方式进行解析的, 如果传入模型进行参数判断, 那也只能校验 json 参数, 所以在 expect 方法中, 除了根据模型, 也可以根据 parser 校验参数. 校验参数的介绍可以看上一篇文章, 或者直接查看 文档 , 使用了 parser 后, 就可以对 表单 , 查询字符串 , 请求头 , 数据类型 等进行校验.
对于 @api.route('/<int:id>') 中的参数, 可以使用 @api.param('id', description='id') 进行渲染. 此装饰器一般用来装饰 资源类 , 上面使用模型的方式一般用来装饰 资源类方法 , 也可以装饰 资源类 , 比如 404 响应, 表示当前类下的每个方法都可能会返回 404 .
使用两篇文章分别介绍了 构建API 和 构建API文档 , 但只是介绍了常用的一些使用方式, 对于更详细和高阶的用法还是需要阅读 文档 . 其实 对象模型 是用来进行序列化的, 我使用起来感觉不太好用, 就只用来生成文档, 对于简单的参数也会用它进行校验. 对于序列化, 我比较喜欢使用 marshmallow , 它的用法和 对象模型 十分相似, 感兴趣可以去看下 文档 .