热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flask搭建api服务

Flask是一个使用Python编写的轻量级Web应用框架,很适合个人开发,我们在此处做一个接口。为方便调试,本文使用get接口方式。get接口十分简单,不需要上传任何数据,在路径后面添加一

Flask是一个使用 Python 编写的轻量级 Web 应用框架,很适合个人开发,我们在此处做一个接口。

为方便调试,本文使用get接口方式。get接口十分简单,不需要上传任何数据,在路径后面添加一个get方法就可以用,返回的是字符串。

本文只是Flask开发的接口的初步文档,从最简单的接口开发到稍微复杂一些的接口,后续如有时间,会逐步完善,包括token鉴权、跨域认证、蓝图应用、日志管理等等。

9f93e13632d9b5a77f3ea76746b87714.png

第一步,首先在configs中配置数据源

configs.py

HOST = '127.0.0.1'
PORT = '5432'
DATABASE = 'runoobdb'
USERNAME = 'postgres'
PASSWORD = '*****'
# 配置主数据库
DB_URI = "postgresql+psycopg2://{username}:{password}@{host}:{port}/{db}".format(username=USERNAME, password=PASSWORD,
                                                                                 host=HOST, port=PORT, db=DATABASE)
# SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://postgres:*****@127.0.0.1:5432/runoobdb'
# 连接其他数据库
SQLALCHEMY_BINDS = {
    'xxxdb': 'postgresql+psycopg2://postgres:123456@localhost:5432/lincms3',
    'yyydb': 'postgresql+psycopg2://postgres:123456@localhost:5432/lincms4',
    'zzzdb': 'sqlite:///users.db'
}
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIOnS= False
SQLALCHEMY_ECHO = True

第二步,在exts中定义全局db

exts.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

第三步,构造了一个flaskutils,在这里定义一些接口应用到的公共类,比如数据转码,将数据集转换为json,解析url逗号参数等等,后续将在此基础上拓展功能。

flaskutils.py

import decimal
 
import numpy as np
import json, datetime,configparser
 
 
class DataEncoder(json.JSONEncoder):
    """数据转码类    """
    def default(self, obj):
        """针对无法转json的数据类型进行转码
        目前支持的转码类型        1、将Numpy的intger,floating转为int和float
        2、将Numpy的ndarray转为list
        3、将np.datetime64转化为字符串前10位        4、将datetime.datetime转化为"%Y-%m-%d %H:%M:%S"
        5、将datetime.date转化为"%Y-%m-%d"
        6、将bytes转化为utf-8字符串
        入参:
            obj: 数据对象
        出参:
            转化后的数据
        异常:
            无        """
        if isinstance(obj, np.integer):
            return int(obj)
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, np.ndarray):
            return obj.tolist()
        elif isinstance(obj, np.datetime64):
            return str(obj)[:10]
        elif isinstance(obj, datetime.datetime):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        elif isinstance(obj, datetime.date):
            return obj.strftime("%Y-%m-%d")
        elif isinstance(obj, decimal.Decimal):
            return float(obj)
        elif isinstance(obj, bytes):
            return str(obj, encoding='utf-8')
        else:
            return json.JSONEncoder.default(self, obj)
 
 
def getsqlresultjson(db, sql,params={}):
    """根据db和sql语句,将结果集转换为json格式
    根据db和sql语句,将结果集转换为json格式
    第一步:根据cursor获取元数据,生成键值列表
    第二步:遍历结果集,将键值列表和结果集组装成字典,加入列表
    第三步:将列表通过DataEncoder进行转码
    入参:
        db: 数据库实例.
        sql: 待运行的SQL语句
    出参:
        Json格式:
        举例:        {'Serak': ('Rigel VII', 'Preparer'),
          'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}
    异常:
        无    """
    resultdict = []
 
    cursor = db.session.execute(sql,params=params).cursor
    resultproxy = db.session.execute(sql,params=params).fetchall()
 
    # 获取元数据
    colname = [i[0] for i in cursor.description]
    # 获取结果集,组成字典,加入列表
    for rowproxy in resultproxy:
        rowresult = dict(zip(colname, rowproxy))
        resultdict.append(rowresult)
 
    # 生成json格式
    jsOnstr= json.dumps(resultdict, cls=DataEncoder)
    return jsonstr
 
 
def parasecommaparamtolist(param):
    '''
    处理in传递参数,in传递参数可适用于两种传递方式,逗号传递参数或参数传递
    此处主要是处理,逗号传递参数,返回为list
    # http://127.0.0.1:5000/getresultbysqlgetparaminbylist?sqlid=sql10&begindate=2018&enddate=2020&kpicode=03010101
    # http://127.0.0.1:5000/getresultbysqlgetparaminbylist?sqlid=sql10&begindate=2018&enddate=2020&kpicode=03010101&kpicode=031111111
    # http://127.0.0.1:5000/getresultbysqlgetparaminbylist?sqlid=sql10&begindate=2018&enddate=2020
    # http://127.0.0.1:5000/getresultbysqlgetparaminbylist?sqlid=sql10&begindate=2018&enddate=2020&kpicode=03010101,222222222
    # http://127.0.0.1:5000/getresultbysqlgetparaminbylist?sqlid=sql10&begindate=2018&enddate=2020&kpicode=03010101&kpicode=03010101
    :param param:
    :return:
        字符串列表    '''
    result = []
    for val in param.split(','):
        if val:
            result.append(val)
    return result

第四步,在app文件构建初始版本

app.py

import configs
from exts import db
from flask import Flask
from flaskutils import *
from flask import request,jsonify
 
app = Flask(__name__)
 
# 加载配置文件
app.config.from_object(configs)
app.debug = True
 
db.init_app(app)
 
if __name__ == '__main__':
    print(app.url_map)
    app.run(host='0.0.0.0', port=8080)

第五步,在app文件中配置sql语句,原本想尝试一下mybis类型的配置文件,后来决定简化;主要包括三条sql,第一条不需要传参,第二条传递常规参数,第三条传递in参数,尤其是in参数,基本上网上找到的方法都不可靠,本文算是原创吧。

sqldict={}
sqldict['sql1'] = """select a.*
from kpi_value a
where a.kpicode in ('01010101','02010101','03010101')
and a.datelevel='01'
and a.regiOnlevel='02'
"""
sqldict['sql2'] = """select a.*
from kpi_value a
where a.kpicode in ('01010101','02010101','03010101')
and a.datelevel='01'
and a.regiOnlevel='02'
and a.datecode>=:begindate and a.datecode<=:enddate
"""
sqldict['sql3'] = """select a.*
from kpi_value a
and a.datelevel='01'
and a.regiOnlevel='02'
and a.datecode>=:begindate and a.datecode<=:enddate
and a.kpicode in :kpicode
"""

1、构造第一个最简单sql返回接口,不需要传递sql参数,但需要传递sqlid参数

@app.route('/getresultbysql', methods=['GET', 'POST'])
def index1():
    sqlid = request.args.get('sqlid')
    sqltext=sqldict[sqlid]
    jsOnstr= getsqlresultjson(db,sqltext)
    return jsonstr, 200, {"Content-Type": "application/json"}

2、构造一个sql内部传参的接口,通过字典参数方式

@app.route('/getresultbysqlparam', methods=['GET', 'POST'])
def index2():
    sqlid = request.args.get('sqlid')
    sqltext=sqldict[sqlid]
    params = {"begindate": '2017',"enddate":'2019'}
    jsOnstr= getsqlresultjson(db,sqltext,params)
    return jsonstr, 200, {"Content-Type": "application/json"}

3、通过url进行sql参数的传递。

@app.route('/getresultbysqlgetparam', methods=['GET', 'POST'])
def index3():
    sqlid = request.args.get('sqlid')
    begindate = request.args.get('begindate')
    enddate = request.args.get('enddate')
    sqltext=sqldict[sqlid]
    params = {"begindate": begindate,"enddate":enddate}
    jsOnstr= getsqlresultjson(db,sqltext,params)
    return jsonstr, 200, {"Content-Type": "application/json"}

4、通过url进行sql参数的传递,不过不传递in参数,而是在路由函数汇总内部指定in参数

@app.route('/getresultbysqlgetparamin', methods=['GET', 'POST'])
def index4():
    sqlid = request.args.get('sqlid')
    sqlid='sql3'
    begindate = request.args.get('begindate')
    enddate = request.args.get('enddate')
    sqltext=sqldict[sqlid]
    incOnd= ['01010101',  '03010101']
    params = {"begindate": begindate,"enddate":enddate,'kpicode':tuple(incond)}
    jsOnstr= getsqlresultjson(db,sqltext,params)
    return jsonstr, 200, {"Content-Type": "application/json"}

5、通过url进行in参数和普通参数的传递,这里可以支持两种方式,一种是&aa=xxx&aa=yyy,一种是aa=xxx,yyy。

@app.route('/getresultbysqlgetparaminbylist', methods=['GET', 'POST'])
def index5():
    sqlid = request.args.get('sqlid')
    sqlid='sql3'
    begindate = request.args.get('begindate')
    enddate = request.args.get('enddate')
    incOnd=request.args.getlist('kpicode')
 
    if len(incond) == 1 and ',' in incond[0]:
        incOnd= parasecommaparamtolist(incond[0])
 
    sqltext=sqldict[sqlid]
    params = {"begindate": begindate,"enddate":enddate,'kpicode':tuple(incond)}
    jsOnstr= getsqlresultjson(db,sqltext,params)
 
    return jsonstr, 200, {"Content-Type": "application/json"}

6、标准化接口响应返回结果。

@app.route('/getresultbysqlgetparaminbylistresponse', methods=['GET', 'POST'])
def index6():
 
    retinfo={}
    errorflag=False
    retinfo['returncode'] = 200
    retinfo['returndata'] = ''
    retinfo['returninfo'] = '处理成果'
    sqlid = request.args.get('sqlid')
    begindate = request.args.get('begindate')
    enddate = request.args.get('enddate')
    incOnd= request.args.getlist('kpicode')
 
    if len(incond) == 1 and ',' in incond[0]:
        incOnd= parasecommaparamtolist(incond[0])
    if not incond:
        retinfo['returninfo']=retinfo['returninfo'] +'未传入KPI编码'
        errorflag=True
    if not begindate:
        retinfo['returninfo'] = retinfo['returninfo'] + '未传入开始时间'
        errorflag=True
    if not enddate:
        retinfo['returninfo'] = retinfo['returninfo'] + '未传入结束时间'
        errorflag=True
    if begindate>enddate:
        retinfo['returninfo'] = retinfo['returninfo'] + '开始时间大于结束时间'
        errorflag=True
    if errorflag==True:
        retinfo['returncode'] = 400
        respOnse= jsonify(retinfo)
        response.status_code = 400
        return response
 
    sqltext = sqldict[sqlid]
    params = {"begindate": begindate, "enddate": enddate, 'kpicode': tuple(incond)}
    jsOnstr= getsqlresultjson(db, sqltext, params)
    retinfo['returndata']  = jsonstr
    respOnse= jsonify(retinfo)
    response.status_code = 200
    return response

推荐阅读
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
author-avatar
平凡我86
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有