极简的多数据源 MySQL 只读 REST 服务。一个 Python 进程可以同时加载多个启用的 profile,调用方先发现
profile,再在每个数据库请求的 URL 中显式指定 profile,不需要记忆端口与数据库环境的对应关系。
所有接口返回 text/plain,不使用 data/message/code 外壳。结果集第一行是字段名,后续是数据行,字段之间
使用 tab 分隔。
安装依赖、创建本地配置并启动:
uv sync
Copy-Item config.example.yaml config.yaml
uv run main.py服务只监听 server.port 配置的一个端口。启动日志会列出当前已启用的 profile。
| 文件 | 说明 |
|---|---|
config.yaml |
本地运行配置,不提交到仓库 |
config.example.yaml |
可复制使用的示例配置 |
配置示例:
app:
name: mysql-readonly-api
sql_log: true
server:
host: 127.0.0.1
port: 8765
reload: false
query:
default_limit: 500
max_limit: 5000
timeout_ms: 15000
profiles:
example-dev:
enabled: true
description: Example development database
mysql:
host: 127.0.0.1
port: 3306
username: readonly
password: password
use_unicode: true
character_encoding: utf8
zero_datetime_behavior: convert_to_null
use_ssl: true
server_timezone: "+08:00"
pool:
size: 5
max_overflow: 10
timeout: 30
recycle: 3600
pre_ping: true
example-prod:
enabled: false
description: Example production read-only database
mysql:
host: 127.0.0.1
port: 13306
username: readonly
password: password
use_unicode: true
character_encoding: utf8
zero_datetime_behavior: convert_to_null
use_ssl: true
server_timezone: "+08:00"
pool:
size: 5
max_overflow: 10
timeout: 30
recycle: 3600
pre_ping: true配置职责:
server只配置当前 REST 服务的监听地址,一个进程只有一份。profiles中的每一项代表一个 MySQL 数据源。enabled: true的 profile 会建立独立的惰性连接池并通过 API 暴露。description会显示在/profiles中,帮助调用方选择正确的数据库环境。- profile 名只能包含小写字母、数字、
-和_。 - 禁用或不存在的 profile 均返回
404 Unknown profile。
服务不配置默认 schema,SQL 中仍需使用 schema.table 明确表名。一个请求只会在 URL 指定的单个 profile
上执行,不能跨 profile 联表。
query.default_limit 是 /query 的默认返回行数;query.max_limit 限制单次最多返回的行数;
query.timeout_ms 会设置 MySQL max_execution_time。offset 默认固定为 0,需要翻页时通过请求参数传入。
app.sql_log: true 时,控制台会打印 SQL 和参数,但不会打印查询结果。
| 接口 | 方法 | 说明 | 参数或请求体 |
|---|---|---|---|
/health |
GET |
检查 REST 服务是否启动 | 无 |
/profiles |
GET |
列出已启用的 profile 及其描述 | 无 |
/profiles/{profile}/schemas |
GET |
列出指定 MySQL 中的业务 schema | 无 |
/profiles/{profile}/tables |
GET |
搜索指定 schema 下的表 | schema 必填,keyword 可选 |
/profiles/{profile}/ddl |
GET |
查看一个或多个表的 IDEA 风格 DDL | schema、table 必填;table 可重复或逗号分隔 |
/profiles/{profile}/query |
POST |
执行只读 SELECT/WITH SQL |
原始 SQL 请求体;offset、limit 可选 |
/profiles/{profile}/count |
POST |
统计查询结果行数 | 原始 SELECT/WITH SQL 请求体 |
/profiles/{profile}/explain |
POST |
查看查询执行计划 | 原始 SELECT/WITH SQL 请求体 |
/profiles 返回示例:
name description
example-dev Example development database
example-prod Example production read-only database
先发现可用 profile:
Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:8765/profiles"查询 profile 中的 schema:
Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:8765/profiles/example-dev/schemas"执行查询:
Invoke-RestMethod `
-Method Post `
-Uri "http://127.0.0.1:8765/profiles/example-dev/query?limit=500" `
-ContentType "text/plain" `
-Body "select * from example_app.orders"项目内置 skill:
skills/mysql-readonly-api
将该目录复制到 Codex skills 目录即可安装。Windows 通常为:
C:\Users\<用户名>\.codex\skills\mysql-readonly-api
skill 会先调用 /profiles 发现数据源,根据 profile 名和描述选择环境,然后在后续每个请求中显式携带该
profile。描述无法消除歧义时,应先向用户确认,不能自行猜测生产或测试环境。
如果 MySQL 只能通过 SSH 服务器访问,可以为每个远程数据源建立不同的本地转发端口:
ssh -N -L 13306:<mysql_host>:<mysql_port> <ssh_user>@<ssh_host>然后把对应 profile 的 MySQL 地址指向本地转发端口:
profiles:
example-prod:
enabled: true
description: Example production read-only database
mysql:
host: 127.0.0.1
port: 13306
# 其余配置省略本地转发终端需要保持运行。这里的 13306 是 MySQL 隧道端口,不是 REST API 端口;所有 profile 仍通过
同一个 REST server.port 访问。
MIT