动作搜索 API:查询规则与 6 种语言
2026-10-02 · 6 min
GET /v1/exercises/search?q= 会对每个动作的名称、目标肌群和器械做全文搜索。它只匹配完整单词,要求你发送的每个词都出现,并按相关度排序。响应语言是另一项独立选择:lang 参数优先,其次是 Accept-Language 请求头,最后是英语,共支持六种语言(en、fr、es、pt、zh、ja)。由于搜索索引建立在英文文本上,请用英文词搜索,再用 lang 控制结果的显示语言。
In short
- 搜索只覆盖名称、目标肌群和器械,不包含动作说明和辅助肌群。
- 只匹配完整单词且全部必需:"squat" 不会匹配 "squats","squat dumbbell" 要求两个词都出现。
- 语言顺序:先看 ?lang=,再看 Accept-Language,最后是英语。不支持的取值会回退到英语,不会报错。
- lang 只改变结果的显示,不会翻译你的搜索词;bodyPart 等筛选参数仍然使用英文取值。
- 响应带有 Content-Language 和 Vary: Accept-Language,缓存时请按语言区分。
动作搜索接口是如何工作的?
携带 API 密钥并发送 q。缺少 q 的请求会返回 400 错误。结果使用与列表接口相同的 { data, pagination } 外层,按相关度排序,相关度相同时按 id 排序。每页默认 50 条,最多 100 条。
curl -H "Authorization: Bearer fed_live_YOUR_KEY" \
"https://api.fitexercisedb.com/v1/exercises/search?q=squat&pageSize=10&lang=fr"每条结果都包含响应字段参考中描述的全部字段。底层是对动作名称、目标肌群和器械的 PostgreSQL 全文查询,除此之外不会索引其他内容。
为什么 "squat" 和 "squats" 的结果不同?
索引使用 PostgreSQL 的 simple 文本配置,它只转为小写,不做词干还原;查询由 plainto_tsquery 构建,它要求每个词都出现。因此查询只匹配完整单词,你发送的每个词都必须存在。
| 查询 | 效果 |
|---|---|
q=squat | 名称、目标肌群或器械中含有单词 squat 的动作 |
q=squat dumbbell | 只返回同时含有两个词的动作 |
q=squ | 不完整的单词没有结果:不支持前缀匹配,所以这不是自动补全接口 |
q=abs | 既匹配目标肌群 Abs,也匹配名称中含 abs 的动作 |
如需输入联想,可以一次性加载你关心的分类和名称,缓存后在本地过滤,最后再用搜索接口做最终查询。编码之前,不妨先在动作数据库里试几个查询,了解数据内容。
搜索能用中文、法语或日语单词吗?
不能靠翻译你的查询实现。被索引的文本是英文的名称、目标肌群和器械,翻译后的名称不在索引中,所以其他语言的词只有在恰好与英文拼写相同时才会匹配。lang 参数改变的是返回的内容,而不是匹配的对象。
本地化搜索框的可行做法是:先自行把用户输入翻译成英文词,再向 API 请求对应语言的文本:
// The user types in French. You map it to English terms, then ask for French text back.
const q = toEnglish("développé couché"); // your own mapping: "bench press"
const url = `/v1/exercises/search?q=${encodeURIComponent(q)}&lang=fr`;常见场景可以干脆不用自由文本:提供部位、肌群和器械的下拉列表,以英文取值作为键,再显示翻译后的标签。
API 如何选择响应语言?
系统按顺序检查三个来源,取第一个受支持的,任何情况都不会报错:
| 顺序 | 来源 | 示例 |
|---|---|---|
| 1 | 查询参数 lang | ?lang=fr |
| 2 | Accept-Language 请求头,从左到右读取 | Accept-Language: fr-FR,fr;q=0.9,en;q=0.8 得到 fr |
| 3 | 默认值 | en |
地区后缀会被忽略,所以 fr-FR 和 pt-BR 分别解析为 fr 和 pt。请求头按书写顺序扫描,采用第一个受支持的标签,不比较质量权重。de 这样的取值不受支持,会悄悄回退到英语。每个响应都会说明所用语言:
Content-Language: fr
Vary: Accept-Language由于同一个 URL 会因 Accept-Language 不同而返回不同文本,请把语言加入缓存键,或者显式发送 lang。
哪些内容会被翻译,哪些保持英文?
| 数据 | 使用 lang 时的行为 |
|---|---|
| bodyPart、target、equipment、secondaryMuscles | 始终按固定词表翻译(10 个部位、19 块目标肌群) |
| name、instructions | 逐个动作翻译,缺少翻译时回退到英文 |
| id、met、热量字段、category、difficulty、mechanic、force | 永远不变 |
| 筛选取值(bodyPart、target、equipment)和 q | 仅限英文 |
最后一行就是陷阱。法语响应会把胸部显示为 Poitrine,但筛选参数需要的是 Chest:
# the filter value stays English, the labels come back in French
curl -H "Authorization: Bearer fed_live_YOUR_KEY" \
"https://api.fitexercisedb.com/v1/exercises?bodyPart=Chest&lang=fr"请在不带 lang 的情况下获取一次筛选列表,并把这些取值当作键保存;完整列表见文档。
FAQ
- 动作搜索会查看动作说明或辅助肌群吗?
- 不会。索引只覆盖名称、目标肌群和器械。若要按辅助肌群筛选,请先取回结果,再在自己的代码里过滤 secondaryMuscles 数组。
- 如果我发送不支持的 lang(例如 de)会怎样?
- API 会回退到英语并返回 200。请查看每个动作的 language 字段或 Content-Language 响应头,确认实际拿到的语言。
- 已经发送 ?lang 还需要 Accept-Language 吗?
- 不需要。lang 查询参数优先,只有在 lang 缺失或不受支持时才会使用 Accept-Language。
- 为什么缓存的响应显示了错误的语言?
- 同一个 URL 会因 Accept-Language 不同而返回不同文本。响应会发送 Vary: Accept-Language,请让你的缓存遵守它,或在 URL 中加入 lang。