Python Flask开发RESTful API:构建规范化的前后端接口
文章目录
- [Python Flask开发RESTful API:构建规范化的前后端接口](#Python Flask开发RESTful API:构建规范化的前后端接口)
-
- 前言
- 一、RESTful设计原则速览
- 二、项目初始化与基础配置
- 三、构建RESTful用户资源接口
-
- [3.1 标准JSON响应封装](#3.1 标准JSON响应封装)
- [3.2 GET - 获取资源列表](#3.2 GET - 获取资源列表)
- [3.3 GET - 获取单个资源](#3.3 GET - 获取单个资源)
- [3.4 POST - 创建资源](#3.4 POST - 创建资源)
- [3.5 PUT - 全量更新资源](#3.5 PUT - 全量更新资源)
- [3.6 DELETE - 删除资源](#3.6 DELETE - 删除资源)
- 四、参数校验:使用Marshmallow
- 五、蓝图(Blueprint):模块化组织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 name、if '@' 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规范能让你的接口更容易被理解和消费。