FitExerciseDB API 响应字段详解
2026-10-02 · 6 min
一个 FitExerciseDB 动作对象共有 16 个字段。其中 5 个一定存在(id、name、bodyPart、target 和 equipment),其余 11 个可能为 null 或缺失,因此客户端应把它们当作可选字段。列表接口把动作放在 data 中并附带 pagination;单个动作的接口会多返回一个 _links 对象;lang 参数只改变文本字段,从不改变数字。本文是 GET /v1/exercises 所返回的 ExerciseDB 风格 JSON 的逐字段参考。
In short
- 每个动作有 16 个字段:id、name、bodyPart、target 和 equipment 为必填,其余都可能为 null。
- id 是形如 "0001" 的四位字符串。请保持字符串类型,以保留前导零。
- caloriesPerMinute 与 averageCaloriesPerMinute 是同一个存储数值;averageCaloriesPerHour 是该数值乘以 60 后取整。针对真实用户,请带上体重调用热量接口。
- 列表返回 { data, pagination }。页数请根据 total 和 pageSize 自行计算。
- 只有单个动作的响应带有 _links。lang 参数只翻译文本字段,不影响数字和枚举值。
动作对象包含哪些字段?
无论在列表中还是单独返回,每个动作都有相同的 16 个字段。5 个必填字段说明这个动作是什么、锻炼哪块肌肉,其余字段补充训练和热量信息。
| 字段 | 类型 | 是否存在 | 说明 |
|---|---|---|---|
id | string | 始终存在 | 四位数字,例如 "0001"。稳定的标识符。 |
name | string | 始终存在 | 动作名称,使用响应语言。 |
bodyPart | string | 始终存在 | 10 个大部位之一,首字母大写,例如 Waist。 |
target | string | 始终存在 | 19 块具体肌肉之一,例如 Abs。 |
equipment | string | 始终存在 | 34 个固定取值之一,例如 "Body Weight"。 |
category | string | 可能为 null | 自由文本标签,例如 strength。 |
difficulty | string | 可能为 null | 例如 beginner。 |
mechanic | string | 可能为 null | 例如 isolation。 |
force | string | 可能为 null | 例如 push。 |
met | number | 可能为 null | 该动作的代谢当量,例如 3.5。 |
caloriesPerMinute | number | 可能为 null | 按典型体重存储的每分钟千卡数。 |
averageCaloriesPerMinute | number | 可能为 null | 与 caloriesPerMinute 数值相同。 |
averageCaloriesPerHour | number | 可能为 null | caloriesPerMinute 乘以 60 后取整。 |
secondaryMuscles | string[] | 可能为 null | 辅助肌群,使用响应语言。 |
instructions | string[] | 可能为 null | 按顺序排列的步骤,使用响应语言。 |
language | string | 可选 | 本次响应所用语言的代码。 |
bodyPart、target 和 equipment 的准确取值来自分类接口,详见 API 文档。
哪些字段可能为 null?客户端该如何处理?
只有 id、name、bodyPart、target 和 equipment 有保证。请把其余 11 个字段建模为可选且可为空,再逐字段决定空值在你的界面上意味着什么。与 API 一致的 TypeScript 类型如下:
type Exercise = {
id: string; // "0001", keep it a string
name: string;
bodyPart: string;
target: string;
equipment: string;
category?: string | null;
difficulty?: string | null;
mechanic?: string | null;
force?: string | null;
met?: number | null;
caloriesPerMinute?: number | null;
averageCaloriesPerMinute?: number | null;
averageCaloriesPerHour?: number | null;
secondaryMuscles?: string[] | null;
instructions?: string[] | null;
language?: "en" | "fr" | "es" | "pt" | "zh" | "ja";
};目前的数据中,全部 1324 个动作的 16 个字段都有值,但数据库结构允许为 null,所以不要依赖这一点。
两条规则能避免大多数 bug。第一,instructions 为 null 时隐藏步骤区块,而不是渲染一个空列表。第二,调用热量接口之前先检查 met:没有 MET 值的动作会返回 422 错误,而不是一个数字。
热量字段与热量接口是什么关系?
caloriesPerMinute 是按典型体重存储的数值,用于在列表中快速展示。averageCaloriesPerMinute 只是它的另一个更直观的名字,averageCaloriesPerHour 则是该数值乘以 60 后取整(每分钟 4.3 千卡对应每小时 258 千卡)。它们都不知道你的用户是谁。
若要个性化估算,请把用户体重和时长传给 GET /v1/exercises/{id}/calories?bodyweightKg=80&minutes=30,它会用该动作的 MET 乘以体重和时间。计算方法与注意事项见 MET 热量指南。MET 数值来自 Compendium of Physical Activities,因此任何结果都只是估算。
列表外层是什么结构?单个动作又多了什么?
列表和搜索共用同一个外层:data 中是数组,pagination 对象包含 page、pageSize 和 total。默认每页 50 条,最大 100 条,所以按最大页容量取完 1,324 个动作需要 14 次请求。我们文档中的部分示例还显示了 totalPages 字段;请自行计算,这样代码在两种情况下都能运行:
{
"data": [ { "id": "0001", "name": "3/4 Sit-up", "bodyPart": "Waist", "target": "Abs", "equipment": "Body Weight" } ],
"pagination": { "page": 1, "pageSize": 50, "total": 1324 }
}const pages = Math.ceil(total / pageSize); // 1324 / 100 = 14单个动作接口 GET /v1/exercises/{id} 返回相同的 16 个字段,另外多一个 HAL 风格的 _links 对象。calories 链接是模板化的,客户端只需填入两个查询参数,无需手写 URL。列表不带 _links。
"_links": {
"self": { "href": "/v1/exercises/0001" },
"related": { "href": "/v1/exercises/0001/related" },
"calories": { "href": "/v1/exercises/0001/calories{?bodyweightKg,minutes}", "templated": true },
"marketplacePreview": { "href": "/marketplace/preview/0001.gif" }
}lang 参数会改变什么?
加上 ?lang=fr(或 es、pt、zh、ja)会翻译 name、bodyPart、target、equipment、secondaryMuscles 和 instructions,并把 language 设为你请求的代码。它不会改动 id、数值字段,也不会改动 category、difficulty、mechanic 和 force 这四个标签,它们保持原样。因此数字只需缓存一次,各语言只需重新获取文本。
语言如何选定,以及为什么搜索词应保持英文,请见搜索与语言指南。想亲自试用,可以浏览动作数据库或阅读文档。 响应里没有图片字段:请看如何购买并嵌入 ExerciseDB GIF和运动 API 的 GIF 与视频支持。
FAQ
- 动作 id 是数字还是字符串?
- 字符串。ID 是带前导零的四位数,例如 "0001" 或 "5201"(编号并不连续)。请以字符串存储和传递,转成数字会丢掉前导零,导致查询失败。
- bodyPart 和 target 是小写吗?
- 不是。取值首字母大写,例如 Waist、Abs 和 Body Weight。筛选参数比较的是这些完整字符串,所以请从分类接口复制,而不是手动输入。
- caloriesPerMinute 取决于用户体重吗?
- 不取决于。它是按典型体重存储的数值。若想得到贴合你用户的数字,请带上 bodyweightKg 和 minutes 调用热量接口。
- 为什么响应里没有总页数?
- pagination 对象保证提供 page、pageSize 和 total。请用 Math.ceil(total / pageSize) 自行计算页数,不要依赖额外字段。