Crear un servidor REST en PHP

En pocas palabras, los servidores REST envían respuestas HTTP basadas en una URL determinada y un verbo HTTP.
Teniendo esto en cuenta, comencemos con el siguiente fragmento de código agregado a rest-service/server/customer/index.php:

<?php
if ('POST' == $_SERVER['REQUEST_METHOD']) {
header('Content-type: application/json');
echo json_encode(['data' => 'Triggered customer POST!']);
}
if ('GET' == $_SERVER['REQUEST_METHOD']) {
header('Content-type: application/json');
echo json_encode(['data' => 'Triggered customer GET!']);
}
if ('PUT' == $_SERVER['REQUEST_METHOD']) {
header('Content-type: application/json');
echo json_encode(['data' => 'Triggered customer PUT!']);
}
if ('DELETE' == $_SERVER['REQUEST_METHOD']) {
header('Content-type: application/json');
echo json_encode(['data' => 'Triggered customer DELETE!']);
}

Por extraño que parezca, este, aquí, ya es un simple ejemplo de servicio REST, uno que maneja cuatro operaciones diferentes para un solo recurso. Usando una herramienta como Postman, podemos activar la operación DELETE en http://rest-service.server/customer/index.php recurso:

Obviamente, esta implementación simplificada no se ocupa de ninguna de las cosas que normalmente encontraría en los servicios REST, como el control de versiones, la normalización, la validación, el intercambio de recursos de origen cruzado (CORS), la autenticación y otros. Implementando todas estas características REST desde cero es una tarea que consume mucho tiempo, por lo que es posible que deseemos echar un vistazo a las soluciones proporcionadas por los frameworks existentes.
Los micro-frameworks de Silex son una solución ordenada para comenzar rápidamente con los servicios REST. Podemos agregar Silex a nuestro proyecto simplemente ejecutando el siguiente comando en la consola, dentro del directorio rest-service/server:

composer require silex/silex "~2.0"

Una vez que lo tengamos instalado, podemos volcar el siguiente código en el archivo rest-service/servidor/index.php:

<?php
require_once __DIR__ . ‘/vendor/autoload.php’;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$app = new Silex\Application();
// The "before" middleware, convenient for auth and request data check
$app->before(function (Request $request, Application $app) {
// Some auth token control
if (!$request->headers->get('X-AUTH-TOKEN')) {
// todo: Implement
}
// JSON content type control
if ($request->headers->get('Content-Type') != 'application/json') {
// todo: Implement
}
});
// The "error" middleware, convenient for service wide error handling
$app->error(function (\Exception $e, Request $request, $code) {
// todo: Implement
});
// The "OPTIONS" route, set to trigger for any URL
$app->options('{url}', function ($url) use ($app) {
return new Response('', 204, ['Allow' => 'POST, GET, PUT, DELETE,
OPTIONS']);
})->assert('url', '.+');
// The "after" middleware, convenient for CORS control
$app->after(function (Request $request, Response $response) {
$response->headers->set('Access-Control-Allow-Headers', 'origin,
content-type, accept, X-AUTH-TOKEN');
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'POST, GET,
PUT, DELETE');
});
// The "POST /user/welcome" REST service endpoint
$app->post('/user/welcome', function (Request $request, Application $app) {
$data = json_decode($request->getContent(), true);
return $app->json(['data' => 'Welcome ' . $data['name']]);
})->bind('user_welcome');
$app->run();

Este también es un ejemplo relativamente simple del servicio REST, pero uno que hace mucho más que nuestro ejemplo inicial. El framework Silex, en este caso, presenta varios conceptos clave que podemos utilizar para nuestro beneficio a medida que construimos nuestro servidor REST. El antes, el después y error middleware nos permite conectarnos en tres etapas distintivas del proceso de manejo de solicitudes. Usando el middleware anterior, podemos inyectar un código de autenticación, por ejemplo, así como varias comprobaciones de la validez de los datos entrantes. Los servicios REST generalmente crean su autenticación en torno a tokens, que luego se pasan a lo largo de solicitudes individuales. La idea general es tener un punto final como usuario/inicio de sesión POST, donde el usuario inicia sesión con su nombre de usuario y contraseña, y luego se le da un token de autenticación para usar con el resto de las llamadas de servicio REST. Este token generalmente se pasa como parte del encabezado de la solicitud. Ahora, cada vez que el usuario intenta acceder a un recurso protegido, se extrae un token del encabezado y se examina en la base de datos (o en cualquier otro almacenamiento donde pueda almacenarse), para descubrir al usuario detrás del token. El sistema le permite al usuario continuar con la solicitud original o la bloquea. Aquí es donde el middleware es útil.

La autenticación del servicio web es un tema enorme en sí mismo. OAuth es el protocolo de autorización estándar de la industria que se usa con bastante frecuencia con los servicios de estilo REST. Para obtener más información sobre OAuth, consulte https://oauth.red.

La forma en que envolvemos nuestras respuestas depende totalmente de nosotros. A diferencia del SOAP, no existe un estándar establecido desde hace mucho tiempo que defina la estructura de datos de la respuesta del servicio REST. Sin embargo, hay varias iniciativas en los últimos años que intentan abordar ese desafío.

La API JSON es un intento de formalizar interfaces cliente-servidor que usan intercambiar datos JSON; echa un vistazo a http://jsonapi.org/format/ para más información.

Para que el servidor funcione correctamente, también debemos agregar el archivo rest-service\server\.htaccess con el siguiente contenido:

<IfModule mod_rewrite.c> Options -MultiViews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] </IfModule>

Silex admite convenientemente varios verbos HTTP clave (GET, POST, PUT, DELETE, PATCH y OPTIONS), para lo cual, podemos implementar fácilmente la lógica en una ruta de recursos + sintaxis de función de devolución de llamada:

$app->get('/resource/path', function () { /* todo: logic */ }); $app->post('/resource/path', function () { /* todo: logic */ }); $app->put('/resource/path', function () { /* todo: logic */ }); $app->delete('/resource/path', function () { /* todo: logic */ }); $app->patch('/resource/path', function () { /* todo: logic */ }); $app->options('/resource/path', function () { /* todo: logic */ });

Esto facilita la redacción rápida de un servicio REST, con solo unas pocas líneas de código. Nuestro ejemplo de servidor hace poco o nada en términos de seguridad del servidor. Su propósito es simplemente enfatizar la utilidad del middleware al construir servicios REST. Aspectos de seguridad tales como autenticación, autorización, CORS, HTTPS y otros deben recibir la máxima atención.

Frameworks como http://silex.sensiolabs.org y https://apigility.org proporcionar una gran solución para escribir servicios REST rico en funciones de alta calidad.

Comparte