← VOLVER AL BLOG

Exercise API: una base de datos abierta, gratuita y bilingüe de ejercicios de gimnasio

Exercise API: una base de datos abierta, gratuita y bilingüe de ejercicios de gimnasio

Casi todos los proyectos que acaban gustándome nacen igual: resolviendo un problema mío. Exercise API no es una excepción.

Tenía un plan de gimnasio —lo llamé Building My Future— y quería documentar cada ejercicio bien: con su nombre en dos idiomas, los músculos que trabaja, una ilustración clara y las instrucciones paso a paso. Cuando fui a buscar una base de datos abierta que me diera todo eso, me encontré con lo de siempre: o estaban de pago, o requerían clave, o venían solo en inglés, o simplemente no existían. Así que hice lo que hacemos los desarrolladores cuando algo no existe: me lo construí.

Lo que empezó como una carpeta con notas se convirtió en una API pública de más de 100 ejercicios, gratis, sin límites y bilingüe. Aquí te cuento qué es, cómo está hecha y por qué creo que puede serte útil.

Qué es exactamente

Exercise API es una base de datos + API abierta de ejercicios de gimnasio. Cada ejercicio trae:

No hay nada que instalar ni registrar. Haces un GET a una URL y recibes JSON. O una imagen. Y ya.

El catálogo actual tiene 104 ejercicios (sigue creciendo), repartidos en 7 grupos (Pecho, Espalda, Hombros, Brazos, Piernas, Core y Cardio), con 15 músculos y 6 tipos de equipamiento.

La decisión de diseño que lo hace tan simple: todo estático

Aquí está la parte que más me gusta contar. Exercise API no tiene servidor.

No hay backend corriendo, ni base de datos que mantener, ni endpoint que se caiga a las tres de la mañana. Todo son archivos estáticos servidos por el CDN de GitHub Pages. Cada “endpoint” es literalmente un archivo JSON que existe en una ruta concreta.

Esto tiene consecuencias muy buenas:

El “truco” es que una API REST bien pensada, para datos que se leen mucho y se escriben poco, no necesita ejecutar código en cada petición. Si puedes precalcular todas las respuestas, un CDN te da escalabilidad infinita por la cara. Y un catálogo de ejercicios es justo eso: se consulta constantemente, cambia muy de vez en cuando.

El versionado va por prefijo /v1/. Si algún día tengo que romper compatibilidad, será en /v2/ y el /v1/ seguirá funcionando para quien ya lo use.

Los endpoints

Al ser todo estático, la lista de endpoints es la lista de archivos:

EndpointQué devuelve
GET /v1/exercises.jsonÍndice de todos los ejercicios (resumidos)
GET /v1/exercises/{slug}.jsonFicha completa de un ejercicio
GET /v1/dataset.jsonTodo en un solo archivo (fichas + taxonomías)
GET /v1/groups.jsonGrupos + conteo
GET /v1/muscles.jsonTaxonomía de músculos
GET /v1/equipment.jsonEquipamientos + conteo
GET /v1/by-group/{group}.jsonEjercicios por grupo
GET /v1/by-muscle/{muscle}.jsonEjercicios por músculo
GET /v1/by-equipment/{type}.jsonEjercicios por equipamiento
GET /images/{slug}-m.jpg · -f.jpgIlustración (hombre / mujer)
GET /muscle-maps/{slug}.svg · -f.svgMapa muscular (hombre / mujer)
GET /exercise-api-dataset.zipTodo en un ZIP (dataset + imágenes + mapas)

Como son archivos, pedir algo que no existe devuelve un honesto HTTP 404. Sin sorpresas.

Una ficha completa se ve así:

{
  "slug": "leg-press",
  "name":  { "es": "Prensa de piernas", "en": "Leg press" },
  "group": { "id": "legs", "es": "Piernas", "en": "Legs" },
  "equipment": { "id": "machine", "es": "Máquina", "en": "Machine" },
  "primaryMuscles":   [ { "id": "quadriceps", "es": "Cuádriceps", "en": "Quadriceps" } ],
  "secondaryMuscles": [ { "id": "gluteal", "es": "Glúteo", "en": "Glutes" } ],
  "instructions": { "es": [ "..." ], "en": [ "..." ] },
  "images": { "male": ".../leg-press-m.jpg", "female": ".../leg-press-f.jpg" },
  "muscleMaps": { "male": ".../leg-press.svg", "female": ".../leg-press-f.svg" }
}

Cómo se construye: un seed y un pipeline

Detrás de la simplicidad de la API hay una pieza que me hizo especial ilusión montar: el generador.

Todo parte de un único archivo, exercises_seed.json, que es la fuente de verdad. Una entrada por ejercicio: slug, nombres, grupo, equipamiento y músculos. A partir de ahí, un script en Python (build_api.py) hace toda la magia:

  1. Redacta las instrucciones en español e inglés usando un modelo de OpenAI, y las cachea para no volver a pagar por lo ya generado.
  2. Dibuja los mapas musculares en SVG a partir de los paths de una librería de código abierto (react-native-body-highlighter, MIT), coloreando el músculo principal y el secundario, en versión masculina y femenina.
  3. Copia las ilustraciones, que se generan aparte con un modelo de texto a imagen siguiendo un estilo canónico fijo (vector plano, fondo blanco, dos fotogramas del movimiento) para que todas las imágenes cuadren entre sí.
  4. Emite todos los JSON: el índice, las fichas, las taxonomías y los cruces por grupo, músculo y equipamiento.

Añadir un ejercicio nuevo es, básicamente: escribir su entrada en el seed, generar sus dos imágenes, correr el generador y hacer commit. GitHub Pages publica solo. Me gusta esta forma de trabajar porque el dato vive en un sitio y todo lo demás se deriva de él. Nada de editar veinte archivos a mano y rezar por no dejarme uno.

Licencia y créditos

La API es de uso libre, incluido el comercial, con una única condición: atribuir la autoría y enlazar al repositorio. Es una licencia estilo MIT con atribución.

Y como los mapas musculares parten de los paths vectoriales de react-native-body-highlighter (© 2022 ELABBASSI Hicham, MIT), su aviso de licencia viaja dentro del repo y del ZIP. Dar crédito a quien te ha ahorrado semanas de trabajo no es solo una obligación legal: es lo mínimo.

Qué viene ahora

El plan es seguir ampliando el catálogo por lotes —siempre faltan ejercicios— y pulir algún detalle de la taxonomía muscular. Pero lo importante ya está: una base de datos de ejercicios abierta, gratuita, bilingüe y sin fricción, que cualquiera puede usar para montar su app de fitness, su tracker de entrenamientos o lo que se le ocurra.

Si construyes algo con ella, me encantaría verlo. Y si te falta un ejercicio, dímelo: probablemente ya esté en la lista de pendientes.