为Flask RestAPI集成Swagger UI

2019-12-30 17:54:33 浏览数 (1)

花了半天时间,给chainhorn集成了Swagger;

虽然这种事情已经做过好几遍了,但是不读文档还是没辙;我把这种半吊子形容为“我认识人民币,但是画不出来…T_T”

还是老老实实流水账记一下吧:

依赖组件

  • flask-restplus

restplus能让人很方便的通过几个decorator就可以集成很漂亮的restapi,它提供了api命名空间、Request和Response解析以及Swagger UI的集成

另外,flask-restplus的文档和例子写的非常简洁清晰,赞一个。

  • flask-httpauth

用来集成验证机制,支持基本的密码验证、Token验证;短小精悍,够用了

起步

引用官网的例子:

构建api对象

1 2 3 4 5 6 7 8 9 10 11 12

from flask import Flask from flask_restplus import Api, Resource, fields from werkzeug.contrib.fixers import ProxyFix app = Flask(__name__) app.wsgi_app = ProxyFix(app.wsgi_app) api = Api(app, version='1.0', title='Chainhorn API', description='A simple ChainHorn API', ) ns = api.namespace('node', description='node operations')

最重要的是构建了api对象,这样就可以为后面的资源增加url路由、参数解析同能;

下面紧跟着构建了一个nsnamespace对象,作用是为不同的资源,不同的url分组,这样最后反映到界面上好看一点;

修饰

1 2 3 4 5 6 7

@ns.route('') class NodeGetInfo(Resource): @ns_node.doc('get node info') def get(self): '''get node info''' info = spv.getinfo() return {'nodeinfo': info}, 200

最简单的,用@ns.route(''),就定义了根url, 然后后面的套路都是相似的,为资源实现get方法,就直接响应 http Get请求了;

Request参数处理

如果直接在url后面跟参数,那么很方便的用 ns.param定义一下即可: 下面这个函数就直接接受一个 /broadcast/tx12345 这样的tx12345作为参数tx

1 2 3 4 5 6 7 8

@ns.route('/broadcast/<string:tx>') class WalletBroadcastTx(Resource): @ns.doc('broadcast raw tx') @ns.param('tx', 'The transaction hash identifier') def post(self, tx): '''broadcast raw tx''' sendrawtransaction(spv, tx) return {'broadcast': 'ok'}, 200

如果要放在FormData里面,可以用ns.expect来限制;它可以接受一个对象传入;比如上面的例子,要把tx字段放到POST请求的Form Data中,要这样做:

1 2 3 4 5 6 7 8 9

TxModel = {'tx': fields.String(required=True, description='The hex tx')} @ns.route('/broadcast') class WalletBroadcastTx(Resource): @ns.doc('broadcast raw tx') @ns.expect(TxModel, 200) def post(self, tx): '''broadcast raw tx''' sendrawtransaction(spv, api.payload['tx']) return {'broadcast': 'ok'}, 200

Response参数处理

同样的,如果需要返回一个对象,在界面上出现这个对象的详细描述信息,可以用marshal_withmarshal_list_with来修饰;

具体请参考:

https://flask-restplus.readthedocs.io/en/stable/parsing.html

用户验证

例如,为API加上HTTP Token Auth,要用到HTTPTokenAuth对象;

首先我们先定义验证规则:

1 2 3 4 5 6 7 8 9 10 11 12 13

auth = HTTPTokenAuth() tokens = { 'APIKEY':'hello', "APPID": "chainhorn" } @auth.verify_token def verify_token(token): if request.headers.get('APIKEY', '').strip()==tokens['APIKEY'] and request.headers.get('APPID', '').strip() == tokens['APPID']: return True else: return False

然后在每个url 请求处理函数前面加上修饰符auth_login_required;比如我们最开始的例子:

1 2 3 4 5 6 7 8 9

@ns.route('') class NodeGetInfo(Resource): @ns.doc('get node info') @auth.login_required def get(self): '''get node info''' info = spv.getinfo() return {'nodeinfo': info}, 200

这样后台验证就有了;那么前台输入呢?

这个例子里面,我们需要前台输入的时候在HTTP Header里面传入两个Key: APIKEY和APPKEY;直接用用Swagger UI自带的组件实现就可以了,把api对象构造为:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

AUTHORIZATIONS = { 'apikey': { 'type': 'apiKey', 'in': 'header', 'name': 'APIKEY' }, 'appid': { 'type': 'apiKey', 'in': 'header', 'name': 'APPID' } } api = Api(app, version='v1', authorizations=AUTHORIZATIONS, security=list(AUTHORIZATIONS.keys()), title='Chainhorn API', description='Chainhorn API', )

这样默认所有的API访问都需要 在HTTP Header中传入两个Key: APIKEY和APPKEY,如果值不对的话就会访问失败;

此时前台的界面是这样的:

可以点击右上角的Authorize一次性设置所有API的访问密钥;

也可以在每个API的右上角设置访问密钥;

当然,我们目前的密钥是后台写死的,你可以引入一个三方库为每个用户生成不同的密钥存到数据库里面,然后每次验证~~~

综合例子

最后,在github上面有个集大成的例子,值得推荐

https://github.com/frol/flask-restplus-server-example

0 人点赞