FitExerciseDB

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 个必填字段说明这个动作是什么、锻炼哪块肌肉,其余字段补充训练和热量信息。

字段类型是否存在说明
idstring始终存在四位数字,例如 "0001"。稳定的标识符。
namestring始终存在动作名称,使用响应语言。
bodyPartstring始终存在10 个大部位之一,首字母大写,例如 Waist。
targetstring始终存在19 块具体肌肉之一,例如 Abs。
equipmentstring始终存在34 个固定取值之一,例如 "Body Weight"。
categorystring可能为 null自由文本标签,例如 strength。
difficultystring可能为 null例如 beginner。
mechanicstring可能为 null例如 isolation。
forcestring可能为 null例如 push。
metnumber可能为 null该动作的代谢当量,例如 3.5。
caloriesPerMinutenumber可能为 null按典型体重存储的每分钟千卡数。
averageCaloriesPerMinutenumber可能为 null与 caloriesPerMinute 数值相同。
averageCaloriesPerHournumber可能为 nullcaloriesPerMinute 乘以 60 后取整。
secondaryMusclesstring[]可能为 null辅助肌群,使用响应语言。
instructionsstring[]可能为 null按顺序排列的步骤,使用响应语言。
languagestring可选本次响应所用语言的代码。

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) 自行计算页数,不要依赖额外字段。