Montar un servidor REST (I)

BLA, BLA, BLA, …

Cuando uno se quiere a poner a programar un juego para móviles, social, con partidas para varios jugadores y de mucho éxito (¡ja¡), lo primero que uno quiere hacer es ponerse a programar la lógica del juego, el tablero, la interacción con este, etc. Apetece algo menos desarrollar el flujo entre pantallas, la pantalla de configuración, el login,… es decir, la fontanería. No es tan “cool”. En lo último que un se piensa meter es el alcantarillado sucio y oscuro del servidor que dará servicio a nuestro juego de éxito. Si uno busca en el diccionario de la programación de juegos en antónimo de “cool”, aparece la palabra “servidor”.

Pero en seguida que uno se pone a programar ese gran éxito, te das cuenta que apenas puedes avanzar si no tienes un servidor contra el que validar usuarios, crear partidas, retar adversarios, configurar notificaciones PUSH, … Un auténtica lata. Así que aquí me encuentro, abandonando la chachi-interfaz de mi super-exito para buscar la mejor forma de escribir un servidor, de la forma más rápida posible y, ya que estamos, que me sirva para cualquier plataforma del mundo-mundial (™) y que pueda reaprovechar para futuros hits. Puedo uno inventarse una personalísima interfaz, con un protocolo propio, o puedo uno aprovechar que ya existe la rueda y montar un servidor REST(casiful). El problema es que puede que usted, como yo, se encuentre con que no tiene ni paj pueñetera idea de cómo montar eso. Después de curiosear por los blogs de otros, ver librerías, framework y más frameworks, uno decide la tontería de escribirse a pelo un mini-framework (o mini-plantilla en realidad) en PHP desde cero; ¡como un machote! Evidentemente como novato habré cometido mil barbaridades, estoy abierto a correcciones y estoy deseando que me las hagan.

Lo primero es explicar rápidamente y sin aburrir de que va eso del REST. Representational State Transfer es un conjunto de convenciones que nos permite interactuar con recursos (Datos, entidades, objetos, …) por medio del protocolo HTTP en un entorno cliente servidor. Es un protocolo no basado en estados por lo que no hay que gestionar sesiones y en el que cada recurso individual o conjunto de recursos puede ser accedido mediante una URI. Para que no entendamos, si quiero leer un conjunto de partidas en mi super-juego, tendré algo así:

http://api.superhitdelamuerte.com/partida

Y si quiero obtener los datos de la partida cuyo ID es 3454, accedería  a la dirección:

http://api.superhitdelamuerte.com/partida/3454

En función de la operación a la que quiera acceder, enviaremos los parámetros en la URL o en el cuerpo de la petición y haremos esta por unos de los métodos contemplado en el protocolo HTTP. Más adelante veremos de nuevo esto.

La respuesta de un servidor REST normalmente es dada en JSON, XML, HTML o algo similar. El cliente debe conocer el formato de la respuesta para poder manejarla.

Hasta aquí una explicación simple y probablemente insuficiente para tus ansias de conocimiento. Te invito a leer más sobre el tema

DÓNDE CARJ PUÑETAS ESTÁ EL CÓDIGO.

Bueno, vamos a la implementación que para eso estamos aquí. Lo primero que vamos a necesitar es escribir un .htaccess (lo siento, no me he puesto a mirarlo para IIS) que haga que toda las peticiones a nuestro servidor sean redirigidas hacia nuestro index.php. Desde allí iremos contruyendo toda nuestra infraestructura. Yo voy a crear subdominios específicos para las api de cada mega-hit que escriba del tipo api.mega-hit.com, de modo que tenga bien separado la API del resto de la web del proyecto, en una carpeta física separada, con sus reglas mod-rewrite particulares. Mi .htaccess tiene este aspecto:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase / 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA]
RewriteRule .* - [E=HTTP_CONTENT_TYPE:%{HTTP:Content-Type},L] 
</IfModule>

Las primeras 5 reglas se encargan de decirle a Apache que redirija todas las peticiones HTTP al index.php. La última regla nos permite acceder al campo de cabecera “Content-Type” desde PHP mediante $_SERVER[‘HTTP_CONTENT_TYPE’].

Una vez que toda petición llega a index.php, debemos analizar la URL de estas para saber que recurso nos están solicitando y si nos están pidiendo una en concreto o un conjunto (recibimos un ID, aunque la desición de hacer una cosa u otra no la tomamos aquí). Debemos averiguar también que tipo de petición es (GET, POST, SET, DELETE) y el formato (content-type) en el que debemos devolver la respuesta, si decidimos que vamos a aceptar más de uno. Yo he escrito mi código para responder con datos en JSON o XML, ya que solo está pensado para que estos sean consumidos por programas y no por humanos.

<?php
// Separamos la URI de los parámetros
$uri= explode('?', $_SERVER['REQUEST_URI']);
// Troceamos la URI: [0] => dominio, [1] => Recurso, [2] => ID
$parts = explode('/', $uri[0]);

// Tipo de petición: GET, POST, PUT, DELETE
$request_method = strtolower($_SERVER['REQUEST_METHOD']);
// Respuesta que vamos a dar.
$content_type = (strpos($_SERVER['HTTP_CONTENT_TYPE'], 'json')) ? 'json' : 'xml';
$data = array();
// Si la petición ha sido de tipo PUT o POST, los datos vienen
// en el cuerpo de la petición. En caso contrario vinen en la
// misma URI.
if ($request_method == "post" || $request_method == "put") 
{
   $values = file_get_contents('php://input');
   parse_str($values, $data);
} 
else 
{
   $data = $_GET;
}

// Si hemos recibido un nombre de recurso...
if(count($parts)>1) {
   // Creamos un objeto de la clase "recursoController"
   // (Ya veremos cómo es esta clase y qué cosas hace)
   $classname = $parts[1]."Controller"; 
   $object = new $classname();

   // Si hemos recibido el ID, lo pasamos al objeto.
   // En caso contrario le pasamos NULL
   $object->ID = isset($parts[2])?$parts[2]:NULL;
   // Pedimos al objeto que procese la petición
   $object->processRequest($request_method, $content_type, $data);
} // No hacemos nada en caso contrario (else)
?>

Así de simple. La parte más dura del trabajo la realiza los objetos de las clases “recursoController” y “recursoModel”. De eso nos ocuparemos en próximas entregas. Lo breve, si bueno, dos veces breve.

2 opiniones en “Montar un servidor REST (I)”

  1. No lo probé, pero cuando le eché un ojo rápido no me pareció que me encajara. Me pareció que solo me cubría la parte de hacer corresponder peticiones a funciones o métodos, y en realidad no me solucionaba gran cosa.

    En realidad estoy tendiendo a usar parse.com y esto lo dejo para usos concretos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *