Servicio web RESTful con PHP

En esta entrada te muestro la implementación de un servicio web RESTful con PHP, que nos permite realizar operaciones CRUD sobre una tabla de usuarios en una base de datos SQLite:

URL HTTP Verb Cuerpo de la petición Resultado
api/usuarios GET Obtener la lista completa de usuarios
api/usuarios/{id} GET Obtener el usuario con el identificador {id}
api/usuarios POST un nuevo usuario Crea el nuevo usuario y lo devuelve en el cuerpo de la respuesta con el id que se le ha asignado
api/usuarios/{id} PUT un usuario existente modificado Modifica el usuario y lo devuelve en el cuerpo de la respuesta
api/usuarios/{id} DELETE Borra el usuario con el identificador {id}

Fichero .htaccess

En un fichero de script PHP, podemos implementar sin grandes dificultades, la gestión de peticiones con los diferentes verbos GET, POST, PUT y DELETE. Pero, necesitamos un sistema de enrutamiento para las url de tipo api/usuarios/{id}. Una solución, sería escribir una regla Rewrite en un fichero .htaccess:

	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule ^(.*)/([0-9]+)$ $1.php [L]

Con esto tanto las peticiones a la URL api/usuarios/{id}, como a la URL api/usuarios se procesan en api/usuarios.php. El id no lo perdemos, porque lo podemos sacar de la variable $_SERVER[‘REQUEST_URI’].

Clase ClienteSQLite – sqlite.php

Para facilitar el acceso a la base de datos SQLite, he creado la siguiente clase:

<?php
class ClienteSQLite
{
	private $lastInsertId=0;
	
	public function Command($comando,$params=array())
	{
		$myArray =array();
		$conn = new PDO('sqlite:../db/dap.db');
		$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		$statement = $conn->prepare($comando);
		$statement->execute($params);
		$this->lastInsertId = $conn->lastInsertId();
		$myArray = $statement->fetchAll(PDO::FETCH_OBJ);
		$conn = null;
		return $myArray;
	}
	
	public function LastInsertId()
	{
		return $this->lastInsertId;
	}
}
?>

Servicio web RESTful – usuarios.php

El código del servicio web RESTful en PHP es el que se muestra a continuación:

<?php
require 'sqlite.php';

/*******RESPUESTA EN FORMATO JSON********/
function sendJSONResponse($body, $statusCode) 
{
	header("Content-Type: application/json; charset=UTF-8");
	http_response_code($statusCode);
	echo(json_encode($body));
}

/*******OBTENER EL IDENTIFICADOR DE LA PETICION REST********/
function getLastPartURL() 
{
	$lastPartURL=array_pop(explode('/', $_SERVER['REQUEST_URI']));
	return	 $lastPartURL;
}

/*******OBTENER EL CUERPO JSON DE LA PETICION HTTP********/
function getJSONBody() 
{
	$inputJSON = file_get_contents('php://input');
	$objeto= json_decode( $inputJSON ); 
	return	 $objeto;
}

/*********SCRIPT CONTROLADOR DE USUARIOS*********/
$clienteSQL=new ClienteSQLite();

switch ($_SERVER['REQUEST_METHOD']) {
	case 'POST':
		try
		{		
			$objeto= getJSONBody() ;
			$params=array(':nombre' => $objeto->Nombre,':password' => $objeto->Password);
			$clienteSQL->Command("INSERT INTO Usuarios (Nombre, Password) VALUES (:nombre,:password)",$params);
			$objeto->UsuarioId=$clienteSQL->LastInsertId();
			sendJSONResponse($objeto,"200");
		}
		catch(Exception $e)
		{
			sendJSONResponse(array("Error al crear usuario"), 500) ;
		}
    break;
	case 'PUT':
		try
		{	
			$lastPartURL=getLastPartURL();
			if (is_numeric($lastPartURL))
			{		
				$objeto= getJSONBody() ;
				$params=array(':id' => $lastPartURL, ':nombre' => $objeto->Nombre,':password' => $objeto->Password);
				$clienteSQL->Command("UPDATE Usuarios SET Nombre=:nombre,Password=:password WHERE UsuarioId=:id",$params);
				sendJSONResponse($objeto,"200");
			}
			else
			{
				sendJSONResponse(array("Formato de URL no válido"), 500) ;
			}
		}
		catch(Exception $e)
		{
			sendJSONResponse(array("Error al actualizar usuario"), 500) ;
		}
    break;
	case 'GET':
		try
		{
			$lastPartURL=getLastPartURL();
			if (is_numeric($lastPartURL))
			{
				$params=array(':id' => $lastPartURL);
				$myArray=$clienteSQL->Command("SELECT * FROM Usuarios WHERE UsuarioId=:id",$params);
				if (count($myArray)==1)
					sendJSONResponse($myArray[0],"200");
				else
					http_response_code(204);
			}
			else
			{
				$myArray=$clienteSQL->Command("SELECT * FROM Usuarios");
				if (count($myArray)>0)
					sendJSONResponse($myArray,"200");
				else
					http_response_code(204);
			}
		}
		catch(Exception $e)
		{
			sendJSONResponse(array("Error al consultar usuario/s"), 500) ;
		}
	break;
	case 'DELETE':
		try
		{
			$lastPartURL=getLastPartURL();
			if (is_numeric($lastPartURL))
			{		
				$params=array(':id' => $lastPartURL);
				$clienteSQL->Command("DELETE FROM Usuarios WHERE UsuarioId=:id",$params);
				http_response_code(204);
			}
			else
			{
				sendJSONResponse(array("Formato de URL no válido"), 500) ;
			}
		}
		catch(Exception $e)
		{
			sendJSONResponse(array("Error al borrar usuario"), 500) ;
		}
	break;
  }
?>