RSP API de Integración

Introducción

El presente informe expone, de forma detallada y con ejemplos, los aspectos técnicos fundamentales de la API de integración con software de terceros del sistema RSP. Pretende, además, servir de guía para que los desarrolladores de dicho software puedan comunicar sus aplicaciones con la infraestructura en la nube de RSP.

En las sucesivas páginas se dan a conocer los diferentes tipos de entidades que maneja el backend de RSP, haciendo especial hincapié en los datos que dichas entidades contienen y cómo se relacionan entre sí. También se expone con ejemplos cómo ha de efectuarse la comunicación con el backend y qué posibilidades ofrece.

Para una mejor comprensión de este documento, se requiere que el lector esté familiarizado con el funcionamiento y la semántica del protocolo HTTP, base fundamental para las comunicaciones con el backend de RSP. También es conveniente poseer un buen conocimiento acerca del funcionamiento y la estructuración de las una REST.

Por último, mencionar que los ejemplos aquí mostrados se muestran de forma agnóstica al lenguaje de programación. Corre a cargo del lector decidir qué lenguaje, librerías o frameworks emplear para la programación del envío de peticiones y del procesado de los mensajes de respuesta.

Definiciones

El sistema RSP cuenta con un conjunto de recursos de computación en la nube cuya misión es la de almacenar los datos de entrenamiento medidos por sus máquinas y aplicaciones móviles, además de toda la gestión de usuarios. A este conjunto de recursos en la nube los denominaremos, en adelante, el backend.

El backend gestiona un conjunto de entidades, que se clasifican de la siguiente manera:

  • Usuarios, que son quienes se registran y tienen acceso al sistema. Típicamente, un entrenador.
  • Atletas, que representan a las personas entrenadas por un usuario. Un usuario puede gestionar los datos de varios atletas.
  • Ejercicios, conteniendo todos los datos de un único ejercicio de un atleta. Aquí se reúnen todos los parámetros de ajuste del ejercicio (tipo de máquina, configuración de masas,

posición del riel, etc.) con los valores medidos por el encoder RSP de todas las repeticiones del ejercicio.

  • Sesiones, o agrupaciones de ejercicios de un mismo atleta dentro de un intervalo de

tiempo.

Toda esta información está disponible a través de una API REST con acceso restringido y que requiere autenticación de usuario. Las peticiones a dicha API se cursan a través de conexiones HTTPS con un host públicamente accesible.

Acceso a la API

El backend de RSP dispone de una API REST que consta de varios endpoints, destinados a diversos usos. Para la integración con terceros, se utiliza el endpoint “ro”; la URL de cualquier solicitud comienza por:

https://backendv2.einercial.com/ro/

La aceptación o rechazo de cualquier petición al sistema depende además de la especificación de una cabecera de autorización HTTP básica; cualquier sistema o aplicación de terceros que quiera operar con ella tendrá que incluir dicha cabecera en todas las llamadas.

Authorization: Basic XXXXXXXXXXXXXXXXX==

El contenido de la cabecera de autorización lleva una clave diferente para cada autorizado, a quien se le habrá facilitado previamente y de forma confidencial dicha clave. (Se recomienda no exponer esta clave para evitar accesos no autorizados o abusos.)

Un ejemplo de acceso a la API se muestra a continuación, donde se pretende autenticar a un usuario (procedimiento de login en el sistema):

GET https://backendv2.einercial.com/ro/login?username=xxxxxxxx&password=yyyyyyyy

Authorization: Basic XXXXXXXXXXXXXXXXX==

Si la acción tiene éxito, se obtendrá una respuesta con código de estado 200 (OK) y datos en formato JSON con información del usuario en cuestión.

Acceso a información privada

Dado que la información que gestiona el backend es de carácter privado, es necesario que dicho usuario haga login en el sistema con sus credenciales para poder acceder a sus datos.

Login de usuario

El proceso de login se realiza mediante una petición GET a la ruta /ro/login. Dicha petición irá acompañada de los parámetros username y password, que serán los correspondientes nombre de usuario y contraseña —respectivamente— del usuario en cuestión.

GET https://backendv2.einercial.com/ro/login?username=xxxxx&password=yyyyy

Authorization: Basic XXXXXXXXXXXXXXXXX==

Ejemplo CURL

curl -X GET \
  -H "Content-Type: application/json" \
  -d '{"username":"demo@rsp.com","password":"demo"}' \
https://backendv2.einercial.com/ro/login

Esta llamada puede tener dos resultados posibles:

  • 200 OK, en el caso de que el login haya sido exitoso.
  • 404 Not Found, si el usuario indicado no existe en el sistema o su contraseña con coincide con la que tiene registrada.

El en caso de haber tenido éxito, la respuesta de la petición contendrá datos en formato JSON similar al que sigue:

{
    'objectId': 'wTBoG37xwR',
    'email':'demo@rsp.com',
    'username':'demo@rsp.com',
    'createdAt':'2023-02-02T09:41:34.060Z',
    'updatedAt':'2023-02-02T09:41:39.596Z',
    'ACL':{
        '*':{'read':true},
        'wTBoG37xwR':{
            'read':true,
            'write':true
        }
    },
    'sessionToken':'r:e50077c62539db3bc3b5ea380183f2ed'
}

Atletas

La API de integración ofrece a los usuarios información acerca de los atletas que entrena. Es posible obtener un listado de todos los que son; o de un subconjunto de ellos, filtrando por diversos campos y/o estableciendo un criterio de ordenación. También se pueden consultar todos los detalles de un atleta concreto.

En ningún caso es posible acceder a los datos de atletas de otros usuarios.

Listado de atletas

Para acceder al listado completo de atletas de un usuario se hará la siguiente petición al sistema:

 GET https://backendv2.einercial.com/ro/classes/Athlete
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Ejemplo CURL

 curl -X GET \
  -H "X-Parse-Session-Token: r:c8f4f967ccb8a11798f122bc9d769aee" \
  -H "Content-Type: application/json" \
  https://backendv2.einercial.com/ro/classes/Athlete 

El resultado de esta petición es un conjunto de datos en formato JSON con los datos de todos los atletas de ese usuario. Entre los datos ofrecidos en la respuesta cabe destacar los siguientes:

{
  "results": [
    {
      "objectId": "vNrEcjGFhu",
      "name": "Demo",
      "coach": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "exercisesCount": 0,
      "minPower": 0,
      "maxPower": 0,
      "createdAt": "2023-02-07T15:05:21.280Z",
      "updatedAt": "2023-02-07T15:05:21.280Z",
      "ACL": {
        "wTBoG37xwR": {
          "read": true,
          "write": true
        }
      }
    }
  ]
}
  • objectID: identificador único del atleta. Se utilizará posteriormente para consultas referidas a ese atleta.
  • coach: contiene el tipo de entidad (_User) y la referencia al usuario del entrenador.
  • name: nombre del atleta.
  • createdAt: fecha de creación del atleta.
  • updatedAt: fecha de la última modificación en los datos del atleta.

Paginación

Nótese que, por defecto, el sistema limita el número de resultados a 100. Para acceder a colecciones más grandes de atletas es posible paginar los resultados incorporando a la petición anterior los parámetros limit y skip. Con limit=k se puede establecer cuántos resultados como máximo se obtendrán: k en este caso. El parámetro skip=n sirve para omitir los primeros n resultados.

GET https://backendv2.einercial.com/ro/classes/Athlete?limit=24&skip=48
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Ejemplo CURL

curl -X GET \
  -H "X-Parse-Session-Token: r:12075fda768ee28106ee0e516cb2b424" \
  -H "Content-Type: application/json" \
  -d '{"limit":1,"skip":1}' \
  https://backendv2.einercial.com/ro/classes/Athlete

Ordenación

Es posible indicar un orden en el que mostrar los resultados de una consulta como la anterior. Para ello, ha de indicarse el parámetro order en la petición. Este parámetro admite una lista de campos separada por comas*, estableciendo como orden principal el primero de ellos. Si alguno de estos campos va precedido por un guión (-), se asumirá que el orden deseado es descendente.

Por ejemplo, si se desea ordenar los resultados por fecha de creación descendente (los más recientes primero), la consulta se articulará de la siguiente manera:

GET https://backendv2.einercial.com/ro/classes/Athlete?order=-createdAt
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Si quisiéramos obtener un listado de atletas ordenados alfabéticamente por nombre y por fecha de creación ascendente, la petición sería:

GET https://backendv2.einercial.com/ro/classes/Athlete?order=name%2CcreatedAt
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

(*) Es importante tener en cuenta que, al codificar el URL de la petición, la coma que separa los campos de ordenación se sustituye por %2C.

Filtrado

El filtrado de resultados en las consultas se formula mediante el parámetro where, que permite especificar la condición o condiciones que deben cumplir los atletas.
Para garantizar la riqueza semántica y la versatilidad de las consultas, where admite condiciones de búsqueda en muy diversa forma. En realidad, admite un objeto JSON serial izado y codificado como parte del URL de la petición. Por ejemplo, si se desea filtrar todos los atletas que hayan sido creados con posterioridad al 1 de enero de 2023 a las 0:00 UTC y que tengan menos de 10 ejercicios contabilizados, el parámetro de búsqueda tendrá la siguiente estructura:

{
  "createdAt": {
    "$gt": {
      "__type": "Date",
      "iso": "2023-01-01T00:00:00.000Z"
    }
  },
  "exercisesCount": {
    "$lt": 10
  }
}

Esto, traducido a una petición HTTP debidamente codificada, queda de la siguiente forma:

GET https://backend.einercial.com/ro/classes/Athlete? where=%7B%0A%20%20%22createdAt%22%3A%20%7B%0A%20%20%20%20%22%24gt%22%3A%20%7B%0A%20%20%20%20%20%20%22__type%22%3A%20%22Date%22%2C%0A%20%20%20%20%20%20%22iso%22%3A%20%222023-01-01T00%3A00%3A00.000Z%22%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22exercisesCount%22%3A%20%7B%0A%20%20%20%20%22%24lt%22%3A%2010%0A%20%20%7D%0A%7D

Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Como puede apreciarse, el valor del parámetro where es la codificación URL del objeto JSON anterior.
También es posible realizar consultas especificando condiciones que no necesariamente deban cumplirse todas, sino sólo alguna de ellas. Esta posibilidad se da gracias al operador especial $or, que permite indicar una lista de condiciones, todas ellas especificadas como se describió anteriormente:

{
  "$or": [
    {
      "name": "Juan"
    },
    {
      "exercisesCount": {
        "$lt": 10
      }
    }
  ]
}

Sesiones planificadas

Las sesiones planificadas por el entrenador que se encuentran almacenados en el backend pueden consultarse de forma similar a los atletas.

Listado de sesiones planificadas de un entrenador

Para obtener un listado de todas las sesiones planificadas de un entrenador hay que formular la siguiente petición al backend:

 GET https://backendv2.einercial.com/ro/classes/ScheduledSession
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Ejemplo CURL

 curl -X GET \
  -H "X-Parse-Session-Token: r:c8f4f967ccb8a11798f122bc9d769aee" \
  -H "Content-Type: application/json" \
  https://backendv2.einercial.com/ro/classes/ScheduledSession 

La respuesta a esta consulta tendrá la siguiente forma:

{
  "results": [
    {
      "objectId": "sfR2nWVdqa",
      "name": "Sesión demo",
      "notes": null,
      "date": {
        "__type": "Date",
        "iso": "2023-02-07T21:36:13.791Z"
      },
      "user": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "createdAt": "2023-02-07T20:37:50.543Z",
      "updatedAt": "2023-02-07T20:39:09.487Z",
      "completed": true,
      "athletes": {
        "__type": "Relation",
        "className": "Athlete"
      }
    }
  ]
}

Paginación, Ordenación y Filtrado

Del mismo modo que para atletas y las sesiones programadas, ordenarlas y limitarlas en número. Las opciones de paginación, ordenación y filtrado respetan el mismo formato de parámetros where, order, limit y skip.
A modo de ejemplo, si se desea obtener un listado de las sesiones pertenecientes a un día en concreto, se procederá con una consulta similar a la siguiente:

{
  "createdAt": {
    "$gt": {
      "__type": "Date",
      "iso": "2023-02-06T00:00:00.000Z"
    },
    "$lt": {
      "__type": "Date",
      "iso": "2023-02-08T00:00:00.000Z"
    }
  }
}

Ejercicios

Los ejercicios realizados por los atletas que se encuentran almacenados en el backend pueden consultarse de forma similar a las sesiones y a los atletas.

Listado de ejercicios de un entrenador

Para obtener un listado de todos los ejercicios de un entrenador hay que formular la siguiente petición al backend:

 GET https://backendv2.einercial.com/ro/classes/Exercise
Authorization: Basic XXXXXXXXXXXXXXXXX==
X-Parse-Session-Token: r:e50077c62539db3bc3b5ea380183f2ed

Ejemplo CURL

 curl -X GET \
  -H "X-Parse-Session-Token: r:c8f4f967ccb8a11798f122bc9d769aee" \
  -H "Content-Type: application/json" \
  https://backendv2.einercial.com/ro/classes/Exercise 

La respuesta a esta consulta tendrá la siguiente forma:

{
  "results": [
    {
      "objectId": "LrOBZrCpUT",
      "repetitions": [ ... ],
      "strokes": [
        {
          "side": true,
          "s": "e",
          "T": 1.72,
          "avgP": 134.30232558139534
        },
        {
          "side": false,
          "s": "c",
          "T": 0.32,
          "avgP": 188.875
        }
      ],
      "coach": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "machineType": "conic",
      "load": 2,
      "loadInox": 2,
      "title": "Preset 1",
      "athlete": {
        "__type": "Pointer",
        "className": "Athlete",
        "objectId": "vNrEcjGFhu"
      },
      "rail": null,
      "sessionTraining": {
        "__type": "Pointer",
        "className": "SessionTraining",
        "objectId": "4zsnBesMGp"
      },
      "serie": 1,
      "asymmetry": 1,
      "training": {
        "__type": "Pointer",
        "className": "Training",
        "objectId": "MnLNrhxAbC"
      },
      "preset": {
        "__type": "Pointer",
        "className": "Preset",
        "objectId": "jOCqWEqmwM"
      },
      "maxPower": 188.875,
      "owner": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "scheduledSession": {
        "__type": "Pointer",
        "className": "ScheduledSession",
        "objectId": "sfR2nWVdqa"
      },
      "createdAt": "2023-02-07T20:38:40.683Z",
      "updatedAt": "2023-02-07T20:38:40.683Z"
    },
    {
      "objectId": "kVcwBJx0N1",
      "repetitions": [  ...  ],
      "strokes": [
        {
          "side": true,
          "s": "e",
          "T": 1.48,
          "avgP": 112.08108108108108
        },
        {
          "side": false,
          "s": "c",
          "T": 0.28,
          "avgP": 141.28571428571428
        }
      ],
      "coach": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "machineType": "conic",
      "load": 2,
      "loadInox": 2,
      "title": "Preset 1",
      "athlete": {
        "__type": "Pointer",
        "className": "Athlete",
        "objectId": "vNrEcjGFhu"
      },
      "rail": null,
      "sessionTraining": {
        "__type": "Pointer",
        "className": "SessionTraining",
        "objectId": "4zsnBesMGp"
      },
      "serie": 2,
      "asymmetry": 1,
      "training": {
        "__type": "Pointer",
        "className": "Training",
        "objectId": "QTSWQNlnF0"
      },
      "preset": {
        "__type": "Pointer",
        "className": "Preset",
        "objectId": "jOCqWEqmwM"
      },
      "maxPower": 246.25,
      "owner": {
        "__type": "Pointer",
        "className": "_User",
        "objectId": "wTBoG37xwR"
      },
      "scheduledSession": {
        "__type": "Pointer",
        "className": "ScheduledSession",
        "objectId": "sfR2nWVdqa"
      },
      "createdAt": "2023-02-07T20:39:07.431Z",
      "updatedAt": "2023-02-07T20:39:07.431Z"
    }
  ]
}

Los campos athlete y coach contienen una referencia al atleta y al entrenador, respectivamente. Otros campos, como machineType o load, indican la configuración de máquina y pesas utilizadas para el ejercicio.

Cada una de las repeticiones que componen el ejercicio se registra dentro de la lista repetitions, que contiene objetos JSON con los datos medidos por la máquina para cada una de esas repeticiones. Cada uno de estos objetos contiene varios valores, como se puede observar en la estructura siguiente:

{
  "side": true,
  "pm": 413,
  "fm": 188,
  "tmf": 0.12,
  "tmp": 0.12,
  "fl": 0,
  "s": -1,
  "fd": 1.48,
  "meanp": 112.08108108108108,
  "pl": 0,
  "spin": 27.769354470673893,
  "bodySide": "none"
}

Paginación, Ordenación y Filtrado

Del mismo modo que para atletas y sesiones se pueden filtrar resultados de ejercicios, ordenarlos y limitarlos en número. Las opciones de paginación, ordenación y filtrado respetan el mismo formato de parámetros where, order, limit y skip.
A modo de ejemplo, si se desea obtener un listado de ejercicios pertenecientes a una sesión determinada, en el where pasaremos el siguiente JSON:

{
"scheduledSession": {
                "__type": "Pointer",
                "className": "ScheduledSession",
                "objectId": "sfR2nWVdqa"
            }
}