10  API REST

10.1 Introducción

En el desarrollo de juegos multijugador modernos, la comunicación entre el cliente y el servidor es fundamental. Después de haber implementado un juego con Phaser 3 el siguiente paso natural es conectar nuestro juego con un servidor mediante una API REST.

En una aplicación web tradicional, el cliente (navegador) se comunica con el servidor utilizando el protocolo HTTP. En aplicaciones web sin AJAX, las peticiones HTTP devuelven un documento HTML que será visualizado por el navegador. Sin embargo, en las aplicaciones con AJAX y las aplicaciones SPA (Single Page Application), las peticiones HTTP se utilizan para intercambiar información entre el navegador y el servidor, pero no HTML.

Las APIs REST permiten esta comunicación mediante el intercambio de datos estructurados. En el contexto de nuestro juego, necesitaremos la API REST para gestionar registro y autenticación de jugadores, almacenamiento de puntuaciones y estadísticas, gestión de partidas y salas de juego, configuración de perfiles de usuario, y consulta de rankings. Posteriormente, cuando implementemos WebSockets (Capítulo 13), usaremos esa tecnología para la comunicación en tiempo real durante el juego, pero la API REST seguirá siendo esencial para todas las operaciones que no requieren actualización instantánea.

Imaginemos nuestra aplicación de juego haciendo una petición HTTP para obtener información de un jugador:

Petición:
GET http://www.mygame.com/players/alice

Respuesta:
{
  "id": "alice",
  "name": "Alice Smith",
  "level": 15,
  "score": 8500,
  "achievements": ["first_win", "speed_demon"]
}

10.2 ¿Qué es una API REST?

REST es un estilo de arquitectura de software basado en HTTP que sigue una serie de principios específicos. Cuando un servicio web cumple estos principios, se denomina RESTful. Una API REST es la interfaz que expone un servidor web para intercambiar información estructurada en lugar de devolver HTML.

El término REST fue acuñado en el año 2000 por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP, en su tesis doctoral. Aunque existen otros tipos de servicios web como SOAP (basados en XML y mucho más complejos), las APIs REST se han convertido en el estándar de facto debido a su simplicidad y eficiencia.

Niveles de madurez REST

Existe un modelo de madurez de Richardson que clasifica las APIs en 4 niveles según su conformidad con los principios REST:

Nivel 0 - The Swamp of POX (Plain Old XML): En este nivel más básico, se usa HTTP simplemente como un sistema de transporte para llamadas a procedimientos remotos. Toda la comunicación se realiza típicamente mediante peticiones POST a una única URL, y el cuerpo de la petición contiene información sobre qué operación realizar. Es similar a usar HTTP como un túnel para otros protocolos (como SOAP). No se aprovecha ninguna característica del protocolo HTTP más allá del transporte.

Nivel 1 - Resources: En este nivel, la API introduce el concepto de recursos individuales. En lugar de tener una única URL para todo, cada recurso tiene su propia URI específica. Por ejemplo, /players/alice y /matches/123 son URIs distintas para recursos diferentes. Sin embargo, todavía se usan métodos HTTP de forma incorrecta, típicamente solo POST para todas las operaciones, sin aprovechar la semántica de GET, PUT, DELETE, etc.

Nivel 2 - HTTP Verbs: Este es el nivel más común y el que usaremos en este curso. Aquí se utilizan correctamente los métodos HTTP (GET para obtener, POST para crear, PUT para actualizar, DELETE para eliminar) y los códigos de estado HTTP (200 para éxito, 404 para no encontrado, 500 para error del servidor, etc.). Este nivel aprovecha plenamente la semántica del protocolo HTTP, haciendo que las APIs sean más intuitivas y fáciles de usar.

Nivel 3 - Hypermedia Controls (HATEOAS): El nivel más avanzado, donde las respuestas incluyen enlaces hipermedia que guían al cliente sobre qué acciones puede realizar a continuación. Por ejemplo, al obtener información de un jugador, la respuesta incluiría enlaces a recursos relacionados como sus partidas, amigos, o acciones disponibles. Este nivel permite que los clientes descubran dinámicamente la API, aunque en la práctica pocas APIs implementan HATEOAS por su complejidad.

En este curso nos centraremos en el Nivel 2 (HTTP Verbs), que es el enfoque más habitual y práctico, donde se hace uso correcto de los métodos HTTP (GET, POST, PUT, DELETE) y códigos de estado.

Un servicio REST ofrece operaciones CRUD (Create, Read, Update, Delete) sobre recursos (ítems de información) del servidor web. Se aprovecha de todos los aspectos del protocolo HTTP: URL, métodos, códigos de estado, cabeceras, etc. La información se intercambia típicamente en formato JSON.

10.3 Casos de Uso de APIs REST

Además de navegadores web, muchos otros tipos de aplicaciones utilizan APIs REST. Las aplicaciones móviles son consumidoras intensivas: la aplicación de Google Maps para Android usa la misma API REST que la versión web, permitiendo mantener una única fuente de verdad en el servidor y consistencia entre plataformas. En comunicación Backend a Backend, un servidor puede consumir APIs REST de otros servidores; por ejemplo, el Aula Virtual de la URJC podría usar la API REST de Google Calendar para publicar eventos. Los videojuegos multijugador utilizan APIs REST para sincronizar estado, gestionar perfiles, implementar matchmaking, guardar partidas en la nube y sistemas de logros, incluyendo juegos en consolas y navegador. Finalmente, dispositivos IoT como Smart TVs, wearables y dispositivos embebidos usan APIs REST para comunicarse con servicios en la nube.

10.4 Formato JSON

JSON (JavaScript Object Notation) es el formato estándar para el intercambio de datos en APIs REST. Es un formato de texto ligero, fácil de leer para humanos y fácil de parsear para máquinas. JSON construye estructuras con dos tipos principales: objetos (colección de pares clave-valor en {}) y arrays (lista ordenada en []). Los valores pueden ser cadenas de texto, números, booleanos, null, objetos o arrays.

{
  "game": {
    "id": "match_12345",
    "type": "pong",
    "status": "active",
    "players": [
      {
        "id": "alice",
        "name": "Alice Smith",
        "score": 5,
        "ready": true
      },
      {
        "id": "bob",
        "name": "Bob Johnson",
        "score": 3,
        "ready": true
      }
    ],
    "settings": {
      "max_score": 11,
      "ball_speed": 300
    }
  }
}

Este ejemplo muestra cómo representar el estado completo de una partida de Pong. JSON también se usa en ficheros de configuración, almacenamiento de datos en disco, y bases de datos NoSQL como MongoDB.

10.5 Funcionamiento de un Servicio REST

El enfoque más habitual en los servicios REST establece cuatro principios fundamentales. En REST, todo es un recurso identificado por una URI única. La URI está compuesta por una parte fija (dominio y ruta base) y una parte variable que identifica el recurso específico. Por ejemplo: http://api.game.com/players/alice, http://api.game.com/matches/12345, http://api.game.com/players/alice/scores, o http://api.game.com/leaderboard.

Los principios de diseño de URIs incluyen usar sustantivos, no verbos (/players/alice ✓ vs /getPlayer?id=alice ✗); usar plurales para colecciones (/players para colección, /players/alice para uno específico); crear jerarquías lógicas (/players/alice/matches refleja relación entre recursos); y usar minúsculas y guiones (/game-sessions/active).

REST aprovecha los métodos HTTP para indicar qué operación realizar sobre un recurso. GET obtiene información, es seguro (no modifica el servidor), idempotente (múltiples peticiones producen el mismo resultado) y cacheable. POST crea nuevos recursos, donde el servidor decide el ID y lo devuelve en la respuesta; no es seguro ni idempotente. PUT actualiza un recurso existente enviando el recurso completo; no es seguro pero sí idempotente. DELETE elimina un recurso; no es seguro pero sí idempotente (eliminar varias veces produce el mismo resultado: el recurso no existe).

La información se intercambia en formato JSON. Una petición HTTP REST completa tiene la siguiente anatomía:

POST /matches HTTP/1.1
Host: api.game.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Length: 89

{
  "type": "pong",
  "mode": "ranked",
  "max_score": 11,
  "player_id": "alice"
}

Esta petición tiene tres partes: la línea de petición (POST /matches HTTP/1.1) indica el método (POST), la ruta (/matches) y la versión HTTP; los headers (cabeceras) son metadatos sobre la petición donde Content-Type: application/json indica que enviamos JSON, Accept: application/json indica que queremos recibir JSON, Authorization: Bearer ... incluye el token de autenticación, y Content-Length: 89 indica el tamaño del cuerpo en bytes; y el body (cuerpo) contiene los datos JSON que enviamos al servidor.

Una respuesta HTTP REST completa tiene la siguiente estructura:

HTTP/1.1 201 Created
Content-Type: application/json
Location: http://api.game.com/matches/67890
Content-Length: 156

{
  "id": "67890",
  "type": "pong",
  "mode": "ranked",
  "max_score": 11,
  "status": "waiting",
  "created_at": "2025-01-15T14:30:00Z",
  "players": ["alice"]
}

Esta respuesta tiene tres partes: la línea de estado (HTTP/1.1 201 Created) indica la versión HTTP, el código de estado (201) y el mensaje (Created); los headers (cabeceras) son metadatos sobre la respuesta donde Content-Type: application/json indica que la respuesta es JSON, Location: http://... proporciona la URI del recurso creado, y Content-Length: 156 indica el tamaño de la respuesta; y el body (cuerpo) contiene los datos JSON del recurso creado.

Los códigos de estado HTTP son números de tres dígitos que comunican el resultado de la operación:

1xx - Respuestas informativas: Indican que la petición fue recibida y el proceso continúa. Raramente usados en REST. El más relevante es 101 Switching Protocols, usado para cambiar de HTTP a WebSockets (Capítulo 13).

2xx - Respuestas exitosas: La petición fue procesada correctamente. Los más comunes son 200 OK (éxito general en GET/PUT), 201 Created (recurso creado tras POST, debería incluir header Location), y 204 No Content (éxito sin contenido, típico en DELETE).

3xx - Redirecciones: El cliente debe tomar acciones adicionales. Incluyen 301 Moved Permanently (recurso movido permanentemente) y 304 Not Modified (usado con caché, el recurso no ha cambiado).

4xx - Errores del cliente: Error en la petición. Los más importantes son 400 Bad Request (petición mal formada), 401 Unauthorized (autenticación requerida), 403 Forbidden (sin permisos), 404 Not Found (recurso no existe), 409 Conflict (conflicto con estado actual, ej: usuario ya existe), y 422 Unprocessable Content (antes Unprocessable Entity; formato correcto pero errores de validación).

5xx - Errores del servidor: El servidor no pudo completar la petición. Los principales son 500 Internal Server Error (error genérico), 503 Service Unavailable (servidor temporalmente no disponible, debe incluir Retry-After), y 504 Gateway Timeout (timeout esperando respuesta de otro servidor).

10.6 Ventajas de esta Arquitectura

En un juego combinaremos la API REST con un canal de comunicación en tiempo real; esta arquitectura híbrida ofrece varias ventajas clave. Proporciona separación de responsabilidades, donde la API REST maneja operaciones de gestión mientras que la lógica del juego se gestiona por separado, permitiendo que cada componente evolucione independientemente. Ofrece escalabilidad, ya que al separar las operaciones de gestión de las de tiempo real, podemos escalar cada servicio según sus necesidades específicas. Mejora la testabilidad, permitiendo probar la API REST de forma independiente al juego, y la lógica del juego puede probarse sin necesidad de conexión a red. Finalmente, proporciona flexibilidad, ya que la misma API REST puede servir a múltiples clientes: el juego web, una aplicación móvil, o herramientas de administración.