前面讲到了Flask实现api,但api是给别人用的,就要告诉别人如何发现api,以及api的用途、名称、出参、入参,生成api文档的做法有好多种,本文选了一种最简单的方式。
核心就是通过app.view_functions 这个字典找到每个API 的endpoint所绑定的方法,然后访问方法的名字和文档即可
从路由中搜索api,在这里可以构筑规则
def get_api_map():
"""Search API from rules, if match the pattern then we said it is API."""
for rule in app.url_map.iter_rules():
if 'docs' not in str(rule) and 'static' not in str(rule):
yield str(rule), rule.endpoint
建立两个路由,一个是api docs的首页,一个是各个api的规则定义
@app.route('/', methods=['GET'])
def index():
"""List all API to this page, api_map contains each api url + endpoint."""
api_map = sorted(list(get_api_map()))
index_url = url_for('index', _external=True)
api_map = [(index_url + x[0][1:], x[1]) for x in api_map]
return render_template('api_index.html', api_map=api_map)
@app.route('/docs/<endpoint>', methods=['GET'])def docs(endpoint):
"""Document page for an endpoint."""
api = {
'endpoint': endpoint,
'methods': [],
'doc': '',
'url': '',
'name': ''
}
try:
func = app.view_functions[endpoint]
api['name'] = _get_api_name(func)
api['doc'] = _get_api_doc(func)
for rule in app.url_map.iter_rules():
if rule.endpoint == endpoint:
api['methods'] = ','.join(rule.methods)
api['url'] = str(rule)
except:
api['doc'] = 'Invalid api endpoint: "{}"!'.format(endpoint)
return render_template('api_docs.html', api=api)
获取api的名称和api文档内容
def _get_api_name(func):
"""e.g. Convert 'do_work' to 'Do Work'"""
words = func.__name__.split('_')
words = [w.capitalize() for w in words]
return ' '.join(words)
def _get_api_doc(func):
if func.__doc__:
return func.__doc__
else:
return 'No doc found for this API!'
在原有的api函数内,补充晚上像个接口定义,包括入参、出参、名称、描述等等
@app.route('/getdimdict', methods=['GET', 'POST'])
def getdimdict():
"""
接口名称: /getdimdict 获取指标库的维度字典
接口描述:
获取指标库的维度字典,
接口入参: get方法
参数无
接口出参: json格式 data = {
"code":"200",
“info":"处理成功"
"result":{
"typecode": "datelevel\",
"typename": "\u65e5\\u671f\\u5c42\\u7ea7\",
"dimcode": "01",
"dimname": "\\u5e74\"
}
}
"""
params = {}
retinfo = {}
errorflag = False
retinfo['code'] = 200
retinfo['info'] = '处理成功'
retinfo['result'] = ''
sqltext = config[DBSECTION]['getdimdict']
jsonstr = getsqlresultjson(db, sqltext, params)
retinfo['result'] = jsonstr
response = jsonify(retinfo)
response.status_code = 200
return response
定义html的base页面-layout.html
{% extends "bootstrap/base.html" %}
{% block title %}Home{% endblock %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
{% endblock %}
{% block content %}
<div id="wrap">
<!-- Begin nav bar -->
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href=" ">API DOC DEMO</ a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active">< a href="/">Home</ a></li>
</ul>
</div>
</div>
</div>
<!-- Begin page content -->
<div class="container">
<ul class="breadcrumb">
<li>< a href="/">Home</ a></li>
{% block breadcrumb_nav %}{% endblock %}
</ul>
<div class="page-header">
{% block page_header %}{% endblock %}
</div>
{% block content_area %}{% endblock %}
</div>
</div>
<div id="footer">
<div class="container">
<p class="text-muted credit">Copyright < a href="https://github.com/tobyqin/">Toby Qin</ a>
- < a href="https://github.com/tobyqin/flask_api_doc">Source at Github</ a></p >
</div>
</div>
{% endblock %}
api_index.html
{% extends "./layout.html" %}
{% block title %}API Root{% endblock %}
{% block breadcrumb_nav %}
<li>< a href="{{ url_for('index') }}">Api Root</ a></li>
{% endblock %}
{% block page_header %}
<h1>Api Root</h1>
{% endblock %}
{% block content_area %}
<pre>{
{% fo