""" 用户 API 路由模块 - 使用 Blueprint 实现模块化路由,避免单文件膨胀 - 包含参数校验、异常处理和分页查询的生产级实现 - 所有数据库写操作均包裹在 try/except 中,失败时自动回滚 """ from flask import Blueprint, request, jsonify from app import db from app.models.user import User # 创建蓝图,名称用于 url_for() 反向解析,__name__ 用于定位模板/静态文件 user_bp = Blueprint('user', __name__) @user_bp.route('', methods=['POST']) def create_user(): """ 创建新用户 - POST /api/users - Body: {"username": "string", "email": "string"} - Returns: 201 + 用户JSON / 400 + 错误信息 / 500 + 服务器错误 """ # silent=True 使得非 JSON 请求体返回 None 而非抛出 400 异常 data = request.get_json(silent=True) # ✅ 入参校验:永远不要信任客户端输入 if not data or 'username' not in data or 'email' not in data: return jsonify({'error': 'Missing required fields: username, email'}), 400 try: user = User(username=data['username'], email=data['email']) db.session.add(user) # commit 同时完成 flush(发送SQL)和事务提交 db.session.commit() return jsonify(user.to_dict()), 201 except Exception as e: # ✅ 异常时必须回滚,否则后续请求复用该 session 会持续报错 db.session.rollback() # 生产环境应记录日志而非直接返回异常详情,此处为模板演示 return jsonify({'error': str(e)}), 500 @user_bp.route('', methods=['GET']) def get_users(): """ 分页获取用户列表 - GET /api/users?page=1&per_page=20 - Returns: 分页结果 JSON,包含 items、total、pages、current_page """ # type=int 确保参数被转换为整数,非法值回退到默认值 page = request.args.get('page', 1, type=int) per_page = request.args.get('per_page', 20, type=int) # paginate() 自动处理 LIMIT/OFFSET,error_out=False 避免页码越界时抛异常 pagination = User.query.order_by(User.created_at.desc()).paginate( page=page, per_page=per_page, error_out=False ) return jsonify({ 'items': [u.to_dict() for u in pagination.items], 'total': pagination.total, # 总记录数 'pages': pagination.pages, # 总页数 'current_page': page, # 当前页码 })