controller路由层与service的调用
- 通过flask_restx 来生成Swagger接口文档
- API接口设计统一使用restful风格
pip安装flask_restx
- 在启动类,server.py定义swaggerAPI初始化文档的内容
code:
# 定义好SwaggerAPI文档的内容和地址
api = Api(app,version="1.0", title="测试平台API接口", description="TestPlatform API", doc="/doc") # 应用程序对象对其进行初始化
- 启动服务,访问:http://127.0.0.1:5000/doc 是可以看到接口定义的内容
- 接下来开始写controller路由层的代码
用户管理的增删改查的路由逻辑
from flask import request, jsonify
from dao.user_dao import UserDAO
from server import api
from util.log_util import Log
from service.user_service import UserService
from flask_restx import Namespace, Resource
# 命名空间
user_ns = Namespace("user", description="用户管理")
userservice = UserService()
log = Log()
"""
路由层,获取前端返回的数据,并传给service层处理
路由层封装接口,使用restful的设计风格
"""
@user_ns.route("")
class UserController(Resource):
get_parser = api.parser() # 添加如下参数:参数以及类型和对象
get_parser.add_argument("id", type=int, location="args")
# 查询接口
@user_ns.expect(get_parser) # 添加命名空间预期的参数
def get(self):
# 拿请求参数用户ID
user_id = request.args.get("id")
log.info(f"接收前端传参 <========{user_id}")
if user_id:
# 查询单个用户信息
# datas查询结果为一个UserDAO对象,进行json格式
# 调用DO层中的as_user_entity_dict(),把python对象转换成前端可以使用的json
datas = userservice.get_filter_user(user_id).as_user_entity_dict() # 调用Service层
return jsonify({"code":0, "msg":"search success","data":datas})
else:
# 否则查询所有用户信息
datas = userservice.get_all_user() # 调用Service层
# 返回的是一个列表对象,需要把它转为json对象,否则前端无法接收
all_data = [data.as_user_entity_dict() for data in datas]
return jsonify({"code":0, "msg":"search success","data":all_data})
put_parser = api.parser() # 添加如下参数:参数以及类型和对象
put_parser.add_argument("id",type=int, required=True, location="json")
put_parser.add_argument("username",type=str, required=True, location="json")
put_parser.add_argument("password",type=str, required=True, location="json")
# 更新接口
@user_ns.expect(put_parser) # 添加命名空间预期的参数
def put(self):
user_data = request.json
log.info(f"接收更新用户的参数<========{user_data}")
userdao = UserDAO(**user_data) # 接受的参数返回值进行解包
res = userservice.update_user(userdao) # 调用Service层
if res:
return jsonify({"code":0, "msg":"update success", "data":res})
else:
return jsonify({"code":40001, "msg":"update fail", "data":res})
post_parser = api.parser() # 添加如下参数:参数以及类型和对象
post_parser.add_argument("id", type=int, required=True, location="json")
post_parser.add_argument("username", type=str, required=True, location="json")
post_parser.add_argument("password", type=str, required=True, location="json")
# 新增接口
@user_ns.expect(post_parser) # 添加命名空间预期的参数
def post(self):
user_data = request.json
log.info(f"接收更新用户的参数<======={user_data}")
userdao = UserDAO(**user_data) # 接受的参数返回值进行解包
res = userservice.create_user(userdao) #调用Service层
if res:
return jsonify({"code":0, "msg":"create success", "data":res})
else:
return jsonify({"code":40001, "msg":"create fail", "data":res})
del_parser = api.parser() # 添加如下参数:参数以及类型和对象
del_parser.add_argument("id", type=int, required=True, location="json")
# 删除接口
@user_ns.expect(del_parser) # 添加命名空间预期的参数
def delete(self):
user_data = request.json
res = user_data.get("id")
log.info(f"接收更新用户的参数<======={res}")
datas = userservice.delete_user(res) #调用Service层
if datas:
return jsonify({"code": 0, "msg": f"user{res} del success"})
else:
return jsonify({"code": 40001, "msg": f"user{res} del fail"})
- controller层逻辑写完后,还需要将user的路由命名空间加到server启动类中,如果不加,在swaggerAPI接口文档中就不会展示出来
server.py中加入一个add_router()的方法,用来把user的namespace加到这里来,并在main中去调用
code:
from flask import Flask
from flask_restx import Api
from flask_sqlalchemy import SQLAlchemy
"""
启动类
"""
app = Flask(__name__)
# todo 应用配置从py文件读取,便于后期维护
app.config.from_object("util.config.Config")
db = SQLAlchemy(app) # 创建SQLAlchemy对象,并与Flask实例建立关联
# 应用程序对象对其进行初始化,定义好SwaggerAPI文档的内容和地址
api = Api(app,version="1.0", title="测试平台API接口", description="TestPlatform API", doc="/doc")
@app.route("/")
def hello_flask():
return "welcome to flask"
# todo 添加路由,把controller的命名空间加到启动类中,否则swagger无法展示API接口
def add_router():
from controller.user_controller import user_ns
api.add_namespace(user_ns,"/user") # 添加api的命名空间,解决swagger不展示内容的问题
if __name__ == "__main__":
add_router()
app.run(debug=True)
- 启动服务,访问swagger接口文档,在接口文档中测试API是否正常
可看到user用户管理空间下有4个接口
分别为:创建用户、修改用户、查询用户、删除用户
- 在swagger中每个API去执行测试
测试删除接口
报错:删除接口报错,出现TypeError: Object of type xxx is not JSON serializable
原因:执行时候日志中数据已经被删除,所以功能是通的,但是在返回值的时候jsonify()方法中,把datas之间传入,datas这个对象是无法序列化,导致代码报错
措施:把datas对象去除,换成res的对象
再次swagger请求删除接口
执行的日志
2023-07-07 10:14:02.632 | INFO | util.log_util:info:10 - 接收更新用户的参数<=======1
2023-07-07 10:14:02,784 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2023-07-07 10:14:02,785 INFO sqlalchemy.engine.Engine [raw sql] {}
2023-07-07 10:14:02,804 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2023-07-07 10:14:02,804 INFO sqlalchemy.engine.Engine [raw sql] {}
2023-07-07 10:14:02,814 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2023-07-07 10:14:02,814 INFO sqlalchemy.engine.Engine [raw sql] {}
2023-07-07 10:14:02,832 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-07-07 10:14:02,836 INFO sqlalchemy.engine.Engine SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password
FROM user
WHERE user.id = %(id_1)s
LIMIT %(param_1)s
2023-07-07 10:14:02,836 INFO sqlalchemy.engine.Engine [generated in 0.00023s] {'id_1': 1, 'param_1': 1}
2023-07-07 10:14:02.847 | INFO | util.log_util:info:10 - 查询单个的内容为:<========<UserDAO 1>
2023-07-07 10:14:02,848 INFO sqlalchemy.engine.Engine SELECT user.id AS user_id, user.username AS user_username, user.password AS user_password
FROM user
WHERE user.id = %(id_1)s
LIMIT %(param_1)s
2023-07-07 10:14:02,848 INFO sqlalchemy.engine.Engine [cached since 0.01272s ago] {'id_1': 1, 'param_1': 1}
2023-07-07 10:14:02.860 | INFO | util.log_util:info:10 - 删除的内容为:<========1
2023-07-07 10:14:02,866 INFO sqlalchemy.engine.Engine DELETE FROM user WHERE user.id = %(id)s
2023-07-07 10:14:02,866 INFO sqlalchemy.engine.Engine [generated in 0.00026s] {'id': 1}
2023-07-07 10:14:02,875 INFO sqlalchemy.engine.Engine COMMIT
删除执行成功,在验证下传入不存在的参数删除,提示:删除失败
测试新增接口
传入未存在的用户ID
传入已经存在的用户ID
测试更新接口
更新已经有用户信息
更新没有的用户信息
测试查询接口
查询单个数据
注意:
# datas查询结果为一个UserDAO对象,进行json格式
# 调用DO层中的as_user_entity_dict(),把python对象转换成前端可以使用的json
datas = userservice.get_filter_user(user_id).user_entity_dict() # 调用Service层
return jsonify({"code":0, "msg":"search success","data":datas}
查询所有数据list
查询单个数据