花了半天时间,给chainhorn集成了Swagger;
虽然这种事情已经做过好几遍了,但是不读文档还是没辙;我把这种半吊子形容为“我认识人民币,但是画不出来…T_T”
还是老老实实流水账记一下吧:
依赖组件
restplus能让人很方便的通过几个decorator就可以集成很漂亮的restapi,它提供了api命名空间、Request和Response解析以及Swagger UI的集成
另外,flask-restplus的文档和例子写的非常简洁清晰,赞一个。
用来集成验证机制,支持基本的密码验证、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路由、参数解析同能;
下面紧跟着构建了一个ns
–namespace
对象,作用是为不同的资源,不同的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_with
和marshal_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