通用数据库REST API服务
Project description
通用多数据库REST API
基于SQLAlchemy Automap的通用多数据库REST API服务,支持动态多数据库连接和管理。
功能特性
- 🗄️ 多数据库支持: 同时连接和管理多个数据库(SQLite、MySQL、PostgreSQL)
- 🔄 动态数据库管理: 运行时添加、移除数据库连接
- 📊 自动表映射: 基于SQLAlchemy Automap自动映射现有表结构
- 🚀 动态表创建: 通过API创建表和索引
- 📤 文件上传: 支持JSON Lines、CSV、Parquet、SQL文件批量导入
- 🔍 复杂查询: 支持多种条件查询操作符
- 📝 完整CRUD: 创建、读取、更新、删除操作
- 🔄 UPSERT操作: 支持Insert or Update (有则更新,无则插入)
- 🎯 自动索引: 可选的自动索引创建以提升查询性能
- 📋 API文档: 自动生成的API文档 (Swagger/OpenAPI)
- 🐳 Docker支持: 完整的容器化部署方案
目录
安装运行
环境要求
- Python 3.8+
- SQLAlchemy 2.0+
- FastAPI
- Uvicorn
安装依赖
# 使用uv (推荐)
uv sync
# 或使用pip
pip install -r requirements.txt
文件上传功能依赖
文件上传功能需要额外的依赖包:
polars: 用于高性能数据处理(替代pandas)pyarrow: 用于处理Parquet文件python-multipart: 用于FastAPI文件上传支持
启动服务
# 开发模式
python run.py
# 或直接运行
uvicorn whatever.main:app --host 0.0.0.0 --port 8000 --reload
服务启动后,访问 http://localhost:8000 查看API文档。
配置说明
环境变量配置
# 默认数据库连接(可选)
DATABASE_URL=sqlite:///./default.db
# 是否显示SQL语句
ECHO_SQL=false
# 多数据库配置(JSON格式)
MULTI_DB_CONFIG='{"db1": {"database_url": "sqlite:///./db1.db", "echo_sql": false}, "db2": {"database_url": "sqlite:///./db2.db"}}'
多数据库配置示例
通过环境变量 MULTI_DB_CONFIG 配置多个数据库:
{
"users_db": {
"database_url": "sqlite:///./users.db",
"echo_sql": false,
"auto_create_tables": true
},
"products_db": {
"database_url": "mysql+pymysql://user:pass@localhost:3306/products",
"echo_sql": true
},
"analytics_db": {
"database_url": "postgresql://user:pass@localhost:5432/analytics"
},
"_default": "users_db"
}
API使用说明
数据库管理
获取数据库列表
GET /databases
添加新数据库
POST /databases
{
"name": "new_db",
"db_type": "sqlite",
"path": "./new_database.db",
"echo_sql": false,
"auto_create_tables": true
}
移除数据库
DELETE /databases/{db_name}
表管理
获取指定数据库的表列表
GET /databases/{db_name}/tables
创建表
POST /databases/{db_name}/tables
{
"table_name": "users",
"columns": {
"name": {"type": "string", "length": 100, "nullable": false},
"email": {"type": "string", "length": 255, "nullable": false},
"age": {"type": "integer", "nullable": true},
"created_at": {"type": "datetime", "nullable": true}
}
}
获取表结构
GET /databases/{db_name}/tables/{table_name}/schema
删除表
DELETE /databases/{db_name}/tables/{table_name}
数据操作
查询数据
# 获取所有记录
GET /databases/{db_name}/tables/{table_name}
# 条件查询
GET /databases/{db_name}/tables/{table_name}?age__gt=25&name__like=张
# 分页查询
GET /databases/{db_name}/tables/{table_name}?limit=10&offset=20
# 自动创建索引
GET /databases/{db_name}/tables/{table_name}?age__gt=20&auto_index=true
插入数据
POST /databases/{db_name}/tables/{table_name}
{
"name": "张三",
"email": "zhangsan@example.com",
"age": 25
}
更新数据
PUT /databases/{db_name}/tables/{table_name}/{record_id}
{
"age": 26,
"email": "new_email@example.com"
}
删除数据
DELETE /databases/{db_name}/tables/{table_name}/{record_id}
索引管理
创建索引
POST /databases/{db_name}/tables/{table_name}/indexes
{
"index_name": "idx_users_email",
"columns": ["email"],
"unique": true
}
UPSERT功能
功能概述
UPSERT操作可以在指定的唯一键或主键发生冲突时更新现有记录,否则插入新记录。这在需要"有则更新,无则插入"的场景中非常有用。
接口设计
为了符合RESTful设计原则,我们使用HTTP PATCH方法实现UPSERT功能:
PATCH /databases/{db_name}/tables/{table_name}/
为什么使用PATCH?
- PATCH语义上就是"部分更新或创建",完美契合UPSERT的需求
- 区别于POST的纯创建语义和PUT的完整替换语义
- 符合RESTful设计原则
基础用法
简单UPSERT(使用默认主键)
# 第一次调用:插入新记录
curl -X PATCH "http://localhost:8000/databases/default/tables/users/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"age": 25
}
}'
# 第二次调用:更新现有记录
curl -X PATCH "http://localhost:8000/databases/default/tables/users/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"age": 26
}
}'
高级UPSERT配置
curl -X PATCH "http://localhost:8000/databases/default/tables/users/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"email": "lisi@example.com",
"name": "李四",
"age": 30,
"created_at": "2024-01-15T10:00:00Z"
},
"conflict_columns": ["email"],
"update_columns": ["name", "age"],
"insert_only_columns": ["created_at"]
}'
参数说明
- data: 要插入或更新的数据(必需)
- conflict_columns: 冲突检测列,不指定则使用主键
- update_columns: 发生冲突时要更新的列,不指定则更新除冲突列外的所有列
- insert_only_columns: 仅在插入时设置的列(如created_at时间戳)
响应格式
{
"success": true,
"action": "insert", // 或 "update"
"message": "新记录已插入", // 或 "记录已更新,共更新 2 个字段"
"database": "default",
"table": "users",
"data": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"age": 25
},
"affected_rows": 1
}
UPSERT使用场景
1. 用户信息同步
# 同步用户信息,存在则更新,不存在则创建
curl -X PATCH "http://localhost:8000/databases/default/tables/users/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"external_id": "ext_123",
"name": "John Doe",
"email": "john@example.com",
"last_sync": "2024-01-15T15:30:00Z"
},
"conflict_columns": ["external_id"],
"update_columns": ["name", "email", "last_sync"]
}'
2. 计数器更新
# 更新统计数据,如果记录不存在则初始化
curl -X PATCH "http://localhost:8000/databases/default/tables/counters/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"counter_name": "page_views",
"value": 1,
"created_at": "2024-01-15T15:30:00Z"
},
"conflict_columns": ["counter_name"],
"update_columns": ["value"],
"insert_only_columns": ["created_at"]
}'
3. 配置管理
# 更新应用配置,不存在则使用默认值
curl -X PATCH "http://localhost:8000/databases/default/tables/settings/" \
-H "Content-Type: application/json" \
-d '{
"data": {
"key": "theme",
"value": "dark",
"updated_at": "2024-01-15T15:30:00Z",
"created_at": "2024-01-15T15:30:00Z"
},
"conflict_columns": ["key"],
"update_columns": ["value", "updated_at"],
"insert_only_columns": ["created_at"]
}'
文件上传
支持的文件格式
- JSON Lines (.jsonl, .ndjson): 每行一个JSON对象
- CSV (.csv): 带表头的CSV文件
- Parquet (.parquet): Parquet列式存储格式
- SQL (.sql): SQL脚本文件
上传文件接口
POST /databases/{db_name}/upload/
使用multipart/form-data格式,支持以下参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| file | file | 是 | - | 要上传的文件 |
| table_name | string | 是 | - | 目标表名 |
| create_table | boolean | 否 | true | 如果表不存在是否自动创建 |
| if_exists | string | 否 | append | 表已存在时的处理方式:append/replace/fail |
| batch_size | integer | 否 | 1000 | 批量插入大小 |
| encoding | string | 否 | utf-8 | 文件编码 |
| csv_delimiter | string | 否 | , | CSV分隔符 |
| csv_quote_char | string | 否 | " | CSV引用字符 |
| sql_batch_execute | boolean | 否 | true | 是否批量执行SQL语句 |
文件上传示例
上传JSON Lines文件:
curl -X POST "http://localhost:8000/databases/default/upload/" \
-F "file=@employees.jsonl" \
-F "table_name=employees" \
-F "create_table=true" \
-F "if_exists=replace"
上传CSV文件:
curl -X POST "http://localhost:8000/databases/default/upload/" \
-F "file=@products.csv" \
-F "table_name=products" \
-F "csv_delimiter=," \
-F "encoding=utf-8"
上传Parquet文件:
curl -X POST "http://localhost:8000/databases/default/upload/" \
-F "file=@orders.parquet" \
-F "table_name=orders" \
-F "create_table=true"
上传SQL文件:
curl -X POST "http://localhost:8000/databases/default/upload/" \
-F "file=@schema.sql" \
-F "table_name=temp" \
-F "sql_batch_execute=false"
获取支持的文件格式信息
GET /databases/{db_name}/upload/formats
快速开始示例
运行文件上传示例脚本:
# 启动API服务
python run.py
# 在另一个终端运行示例
python example_upload.py
或使用完整测试脚本:
python test_upload.py
Docker部署
本项目提供了完整的 Docker 容器化解决方案,包含应用服务、MySQL 数据库和 phpMyAdmin 管理界面。
快速开始
生产环境部署
# 构建并启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
开发环境部署
# 使用开发配置启动(支持代码热重载)
docker-compose -f docker-compose.dev.yml up -d
# 查看应用日志
docker-compose -f docker-compose.dev.yml logs -f app
服务说明
端口映射
-
应用服务: http://localhost:8000
- API 文档: http://localhost:8000/docs
- ReDoc 文档: http://localhost:8000/redoc
-
phpMyAdmin: http://localhost:8080
- 用户名: root
- 密码: whatever123
-
MySQL: localhost:3306
- 数据库: whatever_db
- 用户名: root / whatever_user
- 密码: whatever123
-
Redis (仅开发环境): localhost:6379
数据卷
mysql_data/mysql_dev_data: MySQL 数据持久化redis_data: Redis 数据持久化(开发环境)./uploads: 文件上传目录
Docker环境变量
可以通过 .env 文件或环境变量配置:
# 数据库连接
DATABASE_URL=mysql+aiomysql://root:whatever123@mysql:3306/whatever_db
# SQL 日志
ECHO_SQL=false
# 自动建表
AUTO_CREATE_TABLES=true
# MySQL 配置
MYSQL_ROOT_PASSWORD=whatever123
MYSQL_DATABASE=whatever_db
MYSQL_USER=whatever_user
MYSQL_PASSWORD=whatever123
常用Docker命令
服务管理
# 停止所有服务
docker-compose down
# 停止并删除数据卷
docker-compose down -v
# 重建应用镜像
docker-compose build app
# 只启动特定服务
docker-compose up -d mysql
数据库操作
# 连接 MySQL
docker-compose exec mysql mysql -u root -p
# 导出数据库
docker-compose exec mysql mysqldump -u root -pwhatever123 whatever_db > backup.sql
# 导入数据库
docker-compose exec -T mysql mysql -u root -pwhatever123 whatever_db < backup.sql
# 查看 MySQL 日志
docker-compose logs mysql
应用调试
# 查看应用日志
docker-compose logs -f app
# 进入应用容器
docker-compose exec app bash
# 重启应用服务
docker-compose restart app
Docker自定义配置
MySQL 配置
编辑 docker/mysql/conf.d/custom.cnf 文件来自定义 MySQL 配置。
应用配置
编辑 docker-compose.yml 中的环境变量或创建 .env 文件。
初始化数据
编辑 docker/mysql/init.sql 文件来添加初始化 SQL 脚本。
性能优化
生产环境优化
- 调整 MySQL 内存配置
- 使用外部 Redis 缓存
- 配置 nginx 反向代理
- 启用 MySQL 慢查询日志
开发环境优化
- 使用代码热重载
- 启用 SQL 日志调试
- 使用本地缓存
Docker故障排除
常见问题
-
MySQL 连接失败
# 检查 MySQL 健康状态 docker-compose exec mysql mysqladmin ping -u root -p
-
应用启动失败
# 查看详细日志 docker-compose logs app
-
端口冲突
# 修改 docker-compose.yml 中的端口映射 ports: - "8001:8000" # 修改本地端口
-
数据卷权限问题
# 修复权限 sudo chown -R $USER:$USER uploads/
监控和日志
# 查看所有服务日志
docker-compose logs
# 实时跟踪特定服务日志
docker-compose logs -f mysql
# 查看最近的日志
docker-compose logs --tail=100 app
# 查看资源使用情况
docker stats
查询操作符
支持的查询操作符:
=或column=value: 等于column__gt=value: 大于column__gte=value: 大于等于column__lt=value: 小于column__lte=value: 小于等于column__like=value: 模糊匹配column__in=value1,value2: 包含于列表column__between=value1,value2: 范围查询
支持的数据类型
string: 字符串类型integer: 整数类型float: 浮点数类型boolean: 布尔类型datetime: 日期时间类型text: 长文本类型
使用示例
Python客户端示例
import requests
base_url = "http://localhost:8000"
# 1. 添加新数据库
db_config = {
"name": "my_app_db",
"db_type": "sqlite",
"path": "./my_app.db"
}
response = requests.post(f"{base_url}/databases", json=db_config)
print(response.json())
# 2. 创建表
table_config = {
"table_name": "users",
"columns": {
"name": {"type": "string", "length": 100, "nullable": False},
"email": {"type": "string", "length": 255, "nullable": False},
"age": {"type": "integer", "nullable": True}
}
}
response = requests.post(f"{base_url}/databases/my_app_db/tables", json=table_config)
# 3. 插入数据
user_data = {"name": "张三", "email": "zhangsan@test.com", "age": 25}
response = requests.post(f"{base_url}/databases/my_app_db/tables/users", json=user_data)
# 4. 查询数据
response = requests.get(f"{base_url}/databases/my_app_db/tables/users?age__gt=20")
users = response.json()["data"]
# 5. UPSERT操作
upsert_data = {
"data": {
"email": "zhangsan@test.com",
"name": "张三(更新)",
"age": 26
},
"conflict_columns": ["email"],
"update_columns": ["name", "age"]
}
response = requests.patch(f"{base_url}/databases/my_app_db/tables/users/", json=upsert_data)
curl示例
# 添加数据库
curl -X POST "http://localhost:8000/databases" \
-H "Content-Type: application/json" \
-d '{"name": "test_db", "db_type": "sqlite", "path": "./test.db"}'
# 创建表
curl -X POST "http://localhost:8000/databases/test_db/tables" \
-H "Content-Type: application/json" \
-d '{"table_name": "products", "columns": {"name": {"type": "string"}, "price": {"type": "float"}}}'
# 插入数据
curl -X POST "http://localhost:8000/databases/test_db/tables/products" \
-H "Content-Type: application/json" \
-d '{"name": "笔记本电脑", "price": 5999.99}'
# 查询数据
curl "http://localhost:8000/databases/test_db/tables/products?price__gt=1000"
# UPSERT操作
curl -X PATCH "http://localhost:8000/databases/test_db/tables/products/" \
-H "Content-Type: application/json" \
-d '{"data": {"name": "笔记本电脑", "price": 5599.99}, "conflict_columns": ["name"]}'
测试
运行测试脚本:
# 确保服务正在运行
python run.py
# 在另一个终端运行测试
python test_api.py
技术架构
- FastAPI: 现代Web框架,自动生成API文档
- SQLAlchemy: Python SQL工具包和ORM
- Automap: 自动映射现有数据库表结构
- Pydantic: 数据验证和序列化
- Uvicorn: ASGI服务器
- Polars: 高性能数据处理(用于文件上传)
- Docker: 容器化部署
注意事项
- 数据库连接: 确保目标数据库服务正在运行且可访问
- 权限要求: 确保有足够的数据库权限执行DDL和DML操作
- 主键字段: 创建表时如果没有指定主键,会自动添加
id字段作为主键 - 数据类型: 不同数据库的类型支持可能有差异
- 并发访问: 生产环境建议配置连接池和适当的并发设置
- UPSERT性能: UPSERT操作会先执行查询再决定插入或更新,确保冲突检测列上有适当的索引
- 文件上传: 大文件上传时注意内存使用,建议使用分批处理
最佳实践
UPSERT最佳实践
- 明确指定冲突检测列: 不要依赖默认主键,明确指定业务相关的唯一键
- 合理使用insert_only_columns: 对于时间戳字段,使用insert_only_columns避免意外更新
- 精确控制更新字段: 使用update_columns明确指定哪些字段可以更新
- 错误处理: 在客户端代码中妥善处理各种错误情况
性能优化
- 索引优化: 为常用查询字段创建合适的索引
- 批量操作: 使用文件上传功能进行批量数据导入
- 连接池: 生产环境配置合适的数据库连接池
- 缓存策略: 对于频繁查询的数据考虑使用缓存
贡献
欢迎提交Issue和Pull Request!
许可证
MIT License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rest_whatever-0.5.0.tar.gz.
File metadata
- Download URL: rest_whatever-0.5.0.tar.gz
- Upload date:
- Size: 23.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3643ba61b6902fefe724e13c3a8b771c7b0f07fabfcd45027c39c545d3a9b1ca
|
|
| MD5 |
11bd353ebfbf3b0a248ec8a60171b3b2
|
|
| BLAKE2b-256 |
d383869327cfb317ddbb7525af3e31301f7434c92de39f7b6c3b44e8296e5df9
|
File details
Details for the file rest_whatever-0.5.0-py3-none-any.whl.
File metadata
- Download URL: rest_whatever-0.5.0-py3-none-any.whl
- Upload date:
- Size: 30.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e31b21e432ab20fd8d2b81e37f6412d717fe239b17d9d7a989d4904ddcabb7a3
|
|
| MD5 |
560c57be318e47b9344adc8bbd448d6f
|
|
| BLAKE2b-256 |
0f7390a7b76db462478536752a1c4084b308eb60cfffc9228728669c946f3d15
|