85_Python Flask开发RESTful API

Python Flask开发RESTful API:构建规范化的前后端接口

文章目录

前言

在现代Web开发中,前后端分离 已成为主流架构。前端(React、Vue、小程序)通过HTTP请求与后端通信,后端只需提供RESTful API 接口,返回JSON数据。这种模式下,后端不再关心视图渲染,专注于数据逻辑和业务规则,天然支持多端(Web、App、小程序)共享同一套API。本文将基于Flask,从零构建一个符合REST规范的API系统,涵盖资源设计、JSON响应、参数校验、错误处理和蓝图组织,帮助你写出"别人拿到URL就知道怎么用"的专业API。

RESTful API为什么重要 :如果你给前端同事的接口是一个 /deleteUser?id=1(GET方法执行删除操作),他可能会骂你。REST不是教条,而是一套让团队协作成本最小化的约定------所有人遵循同一套URL设计和HTTP方法语义,文档可以减少80%的沟通成本。面试中能清晰解释GET/POST/PUT/DELETE的语义区别,是后端开发的基本功。

一、RESTful设计原则速览

REST(Representational State Transfer)不是标准而是架构风格,核心原则包括:

  • 资源导向:把一切视为资源(Resource),每个资源有唯一URL
  • 无状态:每个请求包含所有必要信息,服务器不保存客户端状态
  • 统一接口:使用HTTP方法表达操作语义
  • 返回资源表示:返回JSON(或XML)表示的资源状态

HTTP方法与资源操作的对应关系:

HTTP方法 操作 路径示例 说明
GET 查询 /api/users 获取用户列表
GET 查询 /api/users/1 获取ID为1的用户
POST 创建 /api/users 创建新用户
PUT 全量更新 /api/users/1 更新用户全部字段
PATCH 部分更新 /api/users/1 更新用户部分字段
DELETE 删除 /api/users/1 删除用户

二、项目初始化与基础配置

bash 复制代码
mkdir flask_api_demo
cd flask_api_demo
python -m venv venv
# 激活虚拟环境 (Windows)
venv\Scripts\activate
pip install flask

创建基础的Flask API应用:

python 复制代码
# app.py
from flask import Flask, jsonify, request

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False  # 支持中文JSON输出

# 模拟数据库
users = [
    {'id': 1, 'name': '张三', 'email': 'zhangsan@example.com', 'age': 28},
    {'id': 2, 'name': '李四', 'email': 'lisi@example.com', 'age': 32},
    {'id': 3, 'name': '王五', 'email': 'wangwu@example.com', 'age': 25},
]

if __name__ == '__main__':
    app.run(debug=True, port=5000)

JSON_AS_ASCII = False 确保中文在JSON响应中正常显示,而非被转义为 \uXXXX

三、构建RESTful用户资源接口

3.1 标准JSON响应封装

一致的响应格式是API设计的第一步:

python 复制代码
def make_response(data=None, message='success', code=200):
    """统一响应格式"""
    return {
        'code': code,
        'message': message,
        'data': data
    }, code

3.2 GET - 获取资源列表

python 复制代码
@app.route('/api/users', methods=['GET'])
def get_users():
    """获取用户列表"""
    # 支持分页
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 10, type=int)
    
    # 支持搜索
    keyword = request.args.get('q', '')
    if keyword:
        filtered = [u for u in users if keyword in u['name']]
    else:
        filtered = users
    
    # 简单分页
    start = (page - 1) * per_page
    end = start + per_page
    page_data = filtered[start:end]
    
    return jsonify(make_response(data={
        'users': page_data,
        'total': len(filtered),
        'page': page,
        'per_page': per_page
    }))

3.3 GET - 获取单个资源

python 复制代码
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    """获取单个用户"""
    user = next((u for u in users if u['id'] == user_id), None)
    if user is None:
        return jsonify(make_response(
            message=f'用户 {user_id} 不存在', code=404
        )), 404
    return jsonify(make_response(data={'user': user}))

3.4 POST - 创建资源

python 复制代码
@app.route('/api/users', methods=['POST'])
def create_user():
    """创建新用户"""
    data = request.get_json(silent=True)
    
    # 参数校验
    if not data:
        return jsonify(make_response(
            message='请求体不能为空', code=400
        )), 400
    
    name = data.get('name', '').strip()
    email = data.get('email', '').strip()
    
    errors = {}
    if not name:
        errors['name'] = '姓名不能为空'
    if not email or '@' not in email:
        errors['email'] = '邮箱格式不正确'
    
    if errors:
        return jsonify(make_response(
            message='参数校验失败', code=422, data={'errors': errors}
        )), 422
    
    # 创建用户
    new_id = max(u['id'] for u in users) + 1 if users else 1
    new_user = {
        'id': new_id,
        'name': name,
        'email': email,
        'age': data.get('age', 0)
    }
    users.append(new_user)
    
    return jsonify(make_response(
        message='创建成功', code=201, data={'user': new_user}
    )), 201

3.5 PUT - 全量更新资源

python 复制代码
@app.route('/api/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    """全量更新用户"""
    user = next((u for u in users if u['id'] == user_id), None)
    if user is None:
        return jsonify(make_response(
            message=f'用户 {user_id} 不存在', code=404
        )), 404
    
    data = request.get_json(silent=True)
    if not data:
        return jsonify(make_response(message='请求体不能为空', code=400)), 400
    
    # PUT要求提供所有字段
    required = ['name', 'email', 'age']
    for field in required:
        if field not in data:
            return jsonify(make_response(
                message=f'缺少必填字段: {field}', code=422
            )), 422
    
    user['name'] = data['name']
    user['email'] = data['email']
    user['age'] = data['age']
    
    return jsonify(make_response(message='更新成功', data={'user': user}))

3.6 DELETE - 删除资源

python 复制代码
@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    """删除用户"""
    global users
    user = next((u for u in users if u['id'] == user_id), None)
    if user is None:
        return jsonify(make_response(
            message=f'用户 {user_id} 不存在', code=404
        )), 404
    
    users = [u for u in users if u['id'] != user_id]
    return jsonify(make_response(message='删除成功', code=200))

四、参数校验:使用Marshmallow

当接口参数变复杂时(比如创建用户的接口需要校验姓名不为空、邮箱格式正确、年龄在0-150之间),手动写一堆 if not nameif '@' not in email 会让代码迅速膨胀且容易遗漏。Marshmallow 库正是为解决这个问题而生------它将校验规则声明式地写在Schema类中,校验、序列化、反序列化三位一体。

bash 复制代码
pip install marshmallow

Marshmallow的核心概念Schema.load(data)反序列化 ------将JSON字典转为Python对象并执行校验;Schema.dump(obj)序列化 ------将Python对象转为JSON字典。在你的API中,接收请求时用 load() 校验入参,返回响应时用 dump() 格式化出参。这种对称的设计让数据在"客户端的JSON"和"服务端的Python对象"之间无缝穿梭。

python 复制代码
from marshmallow import Schema, fields, ValidationError, validate

class UserSchema(Schema):
    """用户数据校验规则"""
    name = fields.String(required=True, validate=validate.Length(min=1, max=50))
    email = fields.Email(required=True)
    age = fields.Integer(validate=validate.Range(min=0, max=150))

# 在视图函数中使用
@app.route('/api/v2/users', methods=['POST'])
def create_user_v2():
    data = request.get_json(silent=True)
    schema = UserSchema()
    
    try:
        validated = schema.load(data)
    except ValidationError as err:
        return jsonify(make_response(
            message='参数校验失败', code=422, data={'errors': err.messages}
        )), 422
    
    new_user = {
        'id': max(u['id'] for u in users) + 1,
        **validated
    }
    users.append(new_user)
    return jsonify(make_response(message='创建成功', code=201, data={'user': new_user})), 201

Marshmallow 不仅做校验,还能做序列化和反序列化,是RESTful API开发的利器。

五、蓝图(Blueprint):模块化组织API

当API接口增多,全部写在一个文件中会变得难以维护。蓝图允许你按功能模块拆分应用:

python 复制代码
# api/users.py
from flask import Blueprint, request, jsonify

users_bp = Blueprint('users', __name__, url_prefix='/api/users')

# 模拟数据存储(实际项目中使用数据库)
user_list = [...]

@users_bp.route('/', methods=['GET'])
def get_users():
    return jsonify({'users': user_list})

@users_bp.route('/<int:user_id>', methods=['GET'])
def get_user(user_id):
    ...

@users_bp.route('/', methods=['POST'])
def create_user():
    ...

# 注册到app
# app.py
from api.users import users_bp

app.register_blueprint(users_bp)

完整蓝图示例结构

复制代码
flask_api_demo/
├── app.py                  # 应用入口
├── api/
│   ├── __init__.py
│   ├── users.py            # 用户相关接口
│   ├── products.py         # 产品相关接口
│   └── auth.py             # 认证相关接口
└── validators/
    ├── __init__.py
    └── schemas.py          # Marshmallow校验规则

六、错误处理与状态码

优雅的错误处理是成熟API的标志:

python 复制代码
from werkzeug.exceptions import HTTPException

@app.errorhandler(HTTPException)
def handle_http_exception(e):
    """统一处理HTTP异常"""
    response = e.get_response()
    response.data = jsonify(make_response(
        message=e.description, code=e.code
    )).get_data()
    response.content_type = "application/json"
    return response

@app.errorhandler(404)
def not_found(e):
    return jsonify(make_response(message='请求的资源不存在', code=404)), 404

@app.errorhandler(500)
def internal_error(e):
    return jsonify(make_response(message='服务器内部错误', code=500)), 500

总结

构建一个规范化的RESTful API需要关注多个层面:URL设计 要资源导向、名词复数;HTTP方法 要语义清晰;响应格式 要统一规范(code、message、data);参数校验 使用Marshmallow等专业库;应用结构 通过蓝图按模块拆分;错误处理 提供友好的提示信息。这些看似"额外"的工作,在项目规模增长时会带来巨大的维护收益。下一篇我们将转向Django框架入门,体验"大而全"的全栈框架的魅力。

✅ 亮点总结

  • RESTful URL设计遵循"资源导向、名词复数"原则,让API语义清晰、符合直觉
  • 统一的响应格式(code + message + data)是规范化API的基石,前端可据此统一处理
  • Marshmallow序列化器将参数校验与数据序列化合二为一,告别手工校验的繁琐
  • Flask蓝图按功能模块拆分路由,让大型项目的代码结构清晰可维护
  • 全局错误处理器捕获所有异常并返回友好JSON,避免暴露内部细节给客户端

适用场景

  • 移动端API后端:为iOS/Android应用提供数据接口,实现前后端完全分离
  • 微服务架构:每个服务提供独立的RESTful接口,团队可独立开发、部署和扩展
  • 第三方开放平台:对外提供标准化API供合作伙伴集成,遵循REST规范降低对接成本

扩展方向

  • API认证与授权:学习JWT(JSON Web Token)实现无状态的身份认证和权限控制
  • API文档自动化:使用Swagger/OpenAPI(如flasgger、apispec)自动生成可交互的API文档
  • 推荐阅读下一篇《Django框架入门》,体验全栈框架"开箱即用"的强大能力

API设计没有银弹,但遵循REST规范能让你的接口更容易被理解和消费。

相关推荐
cndes10 分钟前
给Miniconda换源,让包下载更迅速
开发语言·python
Metaphor69230 分钟前
使用 Python 添加、隐藏和删除 PDF 图层
python·pdf·图层
丨白色风车丨34 分钟前
【Python 计算机视觉】基于 Dlib+OpenCV 实现实时人眼疲劳检测(闭眼预警)
python·opencv·计算机视觉
嘘嘘出差1 小时前
Python 爬虫入门实战:爬取豆瓣电影 Top 250
开发语言·爬虫·python
爱写代码的倒霉蛋1 小时前
实现协程的三种方式
开发语言·python
崖边看雾2 小时前
记录Python学习——第一章环境安装下载(Windows)
windows·python·学习·pycharm
用户298698530142 小时前
Python 实现 Excel 到 ODS、XPS、PostScript 及 PDF/A-1b 的格式转换
后端·python·excel
本地化文档2 小时前
xlwings-docs-l10n
python·github·excel·gitcode·sphinx
梅雅达编程笔记3 小时前
零基础学 Python 第7章 | 字典 dict:键值对存储
开发语言·python·beautifulsoup·numpy·pandas