Diferencia entre revisiones de «Usuario:ManuelRomero/pruebas»

De WikiEducator
Saltar a: navegación, buscar
 
(12 revisiones intermedias por el mismo usuario no mostrado)
Línea 1: Línea 1:
 +
<!--
 +
;[[#métodos abstractos]]
 +
Son métodos que no tienen código y su implementación se establece al crear una clase que derivada de  la clase que contiene el método abstracto.
 +
#[[#métodos estáticos ]]
 +
*También llamados métodos de la clase, solo se crea una instancia, la cual es compartida por todos los objetos de la misma clase.
 +
*Para poder acceder a un método estático, al igual que en las propiedades estáticas o en las constantes, hay que usar el operador de resolución de ambito [['''''#::''''']]
 +
<source lang=php>
 +
class Lock
 +
{
 +
    private $isLocked = false;
 +
 +
    public function unlock()
 +
    {
 +
        $this->isLocked = false;
 +
        echo 'You unlocked the Lock';
 +
    }
 +
    public function lock()
 +
    {
 +
        $this->isLocked = true;
 +
        echo 'You locked the Lock';
 +
    }
 +
    public function isLocked()
 +
    {
 +
        return $this->isLocked;
 +
    }
 +
}
 +
 +
$aLock = new Lock; // Create object from the class blueprint
 +
$aLock->unlock();  // You unlocked the Lock
 +
$aLock->lock();    // You locked the Lock
 +
</source>
 +
 +
 +
 +
 +
</source>
 +
*Para usar el código anterior
 +
<source lang=php>
 +
 +
$a = new MyClase();
 +
$a->ser_estar();
 +
 +
// Accedo directamente al método de la clase
 +
MyClase::ser_estar();
 +
</source>
 +
*Si desde la propia clase quiero acceder a métodos o atributos estáticos, se usa el operador '''''self'''''
 +
<source lang=php>
 +
class Producto {
 +
    private static $num_productos = 0;
 +
    private $codigo;
 +
//.....
 +
    public funtion ventaProducto($cantidad){
 +
    //Este método podría realizar hacer varias cosas , y luego quiero decrementar elemento
 +
    $this->decrementa($cantidad);
 +
    }
 +
    public function incrementa ($cantidad) {
 +
        self::$num_productos-=$cantidad;
 +
    }
 +
//....
 +
</source>
 +
 +
*Observar la función get_class(), me retorna el nombre del objeto actual si no se le pasa parámetro
 +
http://php.net/manual/es/function.get-class.php
 +
*Observar que para acceder a los diferentes elementos de un objeto se utilizar el operador de indirección '''''->'''''. Esto es por que en realidad el nombre del objeto es una dirección de memoria.
 +
===Funciones para usar con objetos===
 +
*Al igual que get_class(), existen una serie de funciones interesantes que conviene conocer.
 +
*Ver la siguiente referenica
 +
http://php.net/manual/es/ref.classobj.php
 +
 +
 +
 +
===métodos contructor y destructor===
 +
*En php existe un método llamado __construct(..) el cual es invocado siempre que se instancia un objeto.
 +
*Es el constructor, y su invocación es implícita al operador new.
 +
*En PHP5 puedes definir en las clases métodos constructores, que se ejecutan cuando se crea el objeto. El constructor de una clase debe llamarse __construct. Se pueden utilizar, por ejemplo, para asignar valores a atributos.
 +
*Veamos el ejemplo
 +
<source lang=php>
 +
class Producto {
 +
    private static $num_productos = 0;
 +
    private $codigo;
 +
 +
  public function __construct() {
 +
        self::$num_productos++;
 +
    }
 +
    …
 +
}
 +
 +
*El constructor de una clase puede llamar a otros métodos o tener parámetros,
 +
*En este caso  deberán pasarse cuando se crea el objeto.
 +
*Sin embargo, sólo puede haber un método constructor en cada clase. Este concepto es importante tenerlo claro
 +
 +
<source lang=php>
 +
class Producto {
 +
    private static $num_productos = 0;
 +
    private $codigo;
 +
 +
    public function __construct($codigo) {
 +
      $this->$codigo = $codigo;
 +
      self::$num_productos++;
 +
    }
 +
}
 +
$p = new Producto('GALAXYS');
 +
</source>
 +
*Por ejemplo, si como en este ejemplo, definimos un constructor en el que haya que pasar el código, siempre que instanciemos un nuevo objeto de esa clase tendrás que indicar su código.
 +
{{Pregunta|Ahora habría que pensar como implementar la sobre carga de un constructor }}
 +
{{Actividad|
 +
*Realiza una clase para acceso a la base de datos
 +
*Será una forma de reescribir mysqli mas amigable para nosotros
 +
*Podremos conectar.
 +
*Si no pasamos valor por defecto se conectará con los parámetros de siempre (localhost, dwes, root, root
 +
*Verificará usuario en la tabla de usuarios
 +
*Insertará un usuario
 +
*Obtendrá los datos de un producto o de todos
 +
*Realiza luego un programa que utilice esta clase y observa su comodidad.
 
<source lang=php>
 
<source lang=php>
 
<?php
 
<?php
 +
require_once('Producto.php');
  
 +
class DB { 
 +
    public public  __contruct(.....){
 +
    //Este método conecta por defecto con localhost, root root y dwes
 +
    }
 +
    public function ejecutaConsulta($sql) {
 +
    //realiza una consulta
  
class DB {
+
    }
     //atributo privado de conexión
+
 
     private static $conexion;
+
 
 +
     //Obitene todos los productos de la tabla productos y los reotorna en una array
 +
     public function obtieneProductos() {
 
      
 
      
  /*======================conectar()======================================
+
    }
    conecta con la base de datos, usando PDO
+
 
    da valor al atributo privado y estático $conexion de la clase
+
   
    En caso de no conectarse aborta la app y muestra un mensaje
+
    //Obtiene un producto determinado
  ****************************************************************************************** */
+
     public function obtieneProducto($codigo) {
     private static function conectar(){
+
 
        $opc = array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8");
+
    }
        $dsn = "mysql:host=localhost;dbname=dwes";
+
   
        $usuario = 'root';
+
    //Verifica un cliente  para la clase en general
        $contrasena = 'root';
+
    public static function verificaUsuario($nombre, $contrasena) {
        try{
+
 
          $conexion= new PDO($dsn, $usuario, $contrasena, $opc);
+
    }
          $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
    //Verifica un cliente  para la clase en general
        } catch (PDOException $e) {
+
    public static function insertaUsuario($nombre, $contrasena) {
                die ('Abortamos la aplicación por fallo conectando con la BD' . $e->getMessage());
+
 
        }
+
        self::$conexion = $conexion;
+
 
      
 
      
 
}
 
}
  
 +
?>
 +
</source>
  
/*======================ejecutaConsulta ($sql,$valores)======================================
+
<source lang=php>
    Accion: Ejecuta una consulta preparada con los valores de los parámetros de la consulta preparada
+
<?php
    Parámetros: $sql es la consulta preparada y parametrizada
+
require_once('Producto.php');
                $valores es un array asociativo con los valores de los distintos
+
 
                          parámetros de la consulta anterior
+
class DB {  
    Retorna =La consulta despues de ejecutarla, o null si no la ha podido ejecutaqr
+
     protected static function ejecutaConsulta($sql) {
            en caso de no ejecutarla da un mensaje             
+
         $opc = array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8");
  * ***********************************************************************************************/
+
        $dsn = "mysql:host=localhost;dbname=dwes";
     protected static function ejecutaConsulta($sql,$valores) {
+
        $usuario = 'dwes';
         if (self::$conexion == null)
+
        $contrasena = 'abc123.';
            self::conectar();
+
       
      $conexion = self::$conexion;
+
        $dwes = new PDO($dsn, $usuario, $contrasena, $opc);
      try{
+
        $resultado = null;
          $consulta = $conexion->prepare($sql);
+
        if (isset($dwes)) $resultado = $dwes->query($sql);
          $consulta->execute($valores);
+
        return $resultado;
      } catch (PDOException $e) {
+
          echo 'No se ha podido ejecutar la consulta' . $e->getMessage();
+
          return null;
+
        }
+
      return $consulta;
+
     
+
 
     }
 
     }
  
 +
    public static function obtieneProductos() {
 +
        $sql = "SELECT cod, nombre_corto, nombre, PVP FROM producto;";
 +
        $resultado = self::ejecutaConsulta ($sql);
 +
        $productos = array();
  
/*======================verificaCliente ($nombre,$pass)======================================
+
if($resultado) {
    Accion: verifica si un nombre y pass son contenidos en la base de datos
+
            // Añadimos un elemento por cada producto obtenido
    Parámetros: $nombre es el nombre de usuario
+
            $row = $resultado->fetch();
                $pass es la password para ese nombre
+
            while ($row != null) {
     Retorna  true o false según se haya podido o no validar
+
                $productos[] = new Producto($row);
  * Recordar que la pass está cifrada con md5 en la base de datos     
+
                $row = $resultado->fetch();
* ***********************************************************************************************/ 
+
            }
     public static function verificaCliente($nombre, $pass) {
+
}
      $valores = array('usuario'=>$nombre, 'password' =>$pass);
+
       
         $sql = <<<FIN
+
        return $productos;
         SELECT usuario FROM usuarios  
+
     }
         WHERE usuario=:usuario
+
 
         AND contrasena=md5(:password)
+
   
FIN;
+
     public static function obtieneProducto($codigo) {
         $resultado = self::ejecutaConsulta ($sql,$valores);
+
        $sql = "SELECT cod, nombre_corto, nombre, PVP FROM producto";
 +
        $sql .= " WHERE cod='" . $codigo . "'";
 +
        $resultado = self::ejecutaConsulta ($sql);
 +
        $producto = null;
 +
 
 +
if(isset($resultado)) {
 +
            $row = $resultado->fetch();
 +
            $producto = new Producto($row);
 +
}
 +
          
 +
        return $producto;   
 +
    }
 +
   
 +
    public static function verificaCliente($nombre, $contrasena) {
 +
         $sql = "SELECT usuario FROM usuarios ";
 +
         $sql .= "WHERE usuario='$nombre' ";
 +
         $sql .= "AND contrasena='" . md5($contrasena) . "';";
 +
         $resultado = self::ejecutaConsulta ($sql);
 
         $verificado = false;
 
         $verificado = false;
      if ($resultado->fetch())
+
 
          $verificado=true;
+
        if(isset($resultado)) {
 +
            $fila = $resultado->fetch();
 +
            if($fila !== false) $verificado=true;
 +
        }
 
         return $verificado;
 
         return $verificado;
 
     }
 
     }
}//End de la clase DB.php
+
   
 +
}
  
 
?>
 
?>
 
</source>
 
</source>
 +
 +
}}
 +
-->
 +
 +
 +
 +
 +
 +
 +
= Introducción a REST =
 +
 +
REST al igual que otras tecnologías, como Git y CSS, requiere un poco de tiempo para su comprensión. En este breve manual nos centraremos en la filosofía que está detrás de REST(así como sus diferencias con SOAP), y en los aspectos prácticos. ¿Cómo podemos implementar REST hoy?
 +
 +
== ¿Que es es REST? ==
 +
 +
 +
'''REST''' son las siglas de '''Representational State Transfer'''. Fue definido hace una década por Roy Fielding en su tesis doctoral, y proporciona una forma sencilla de interacción entre sistemas, la mayor parte de las veces a través de un navegador web y HTTP. Esta cohesión con HTTP viene también de que Roy es uno de los principales autores de HTTP.
 +
 +
REST es un estilo arquitectónico, un conjunto de convenciones para aplicaciones web y servicios web, que se centra principalmente en la manipulación de recursos a través de especificaciones HTTP. Podemos decir que REST es una interfaz web estándar y simple que nos permite interactuar con servicios web de una manera muy cómoda.
 +
 +
Gracias a REST la web ha disfrutado de escalabilidad como resultado de una serie de diseños fundamentales clave:
 +
* Un '''protocolo cliente/servidor sin estado''': cada mensaje HTTP contiene toda la información necesaria para comprender la petición. Como resultado, ni el cliente ni el servidor necesitan recordar ningún estado de las comunicaciones entre mensajes. Sin embargo, en la práctica, muchas aplicaciones basadas en HTTP utilizan cookies y otros mecanismos para mantener el estado de la sesión (algunas de estas prácticas, como la reescritura de URLs, no son permitidas por REST).
 +
* Un '''conjunto de operaciones bien definidas''' que se aplican a todos los recursos de información: HTTP en sí define un conjunto pequeño de operaciones, las más importantes son '''POST''', '''GET''', '''PUT''' y '''DELETE'''. Con frecuencia estas operaciones se equiparan a las operaciones CRUD que se requieren para la persistencia de datos, aunque POST no encaja exactamente en este esquema.
 +
 +
* Una '''sintaxis universal para identificar los recursos'''. En un sistema REST, cada recurso es direccionable únicamente a través de su URI.
 +
 +
* El '''uso de hipermedios''', tanto para la información de la aplicación como para las transiciones de estado de la aplicación: la representación de este estado en un sistema REST son típicamente HTML o XML. Como resultado de esto, es posible navegar de un recurso REST a muchos otros, simplemente siguiendo enlaces sin requerir el uso de registros u otra infraestructura adicional.
 +
 +
 +
Vamos a ver primero lo que son las URIs. Una URI es esencialmente un identificador de un recurso. Veamos el siguiente ejemplo:
 +
<syntaxhighlight lang='bash'>
 +
GET /amigos
 +
</syntaxhighlight>
 +
 +
Podríamos llamar a esto un recurso. Cuando esta ruta es llamada, siguiendo los patrones REST, se obtendrán todos los amigos (generalmente de una base de datos), y se mostrarán en pantalla o se devolverán en un formato determinado a quien lo solicite.
 +
 +
Pero, cómo haremos si queremos especificar un amigo en particular?.
 +
<syntaxhighlight lang='bash'>
 +
GET /amigos/marta
 +
 +
</syntaxhighlight>
 +
 +
 +
Como se puede ver es fácilmente comprensible. Esa es una de las claves de la arquitectura RESTful. Permite el uso de URIs que son fácilmente comprensibles por los humanos y las máquinas.
 +
 +
Piensa en un recurso como un nombre en plural. Contactos, estados, usuarios, fotos --- todos éstos serían elecciones perfectas.
 +
 +
Hasta ahora, hemos visto como identificar a una colección y a elementos individuales en esa colección:
 +
 +
<syntaxhighlight lang='bash'>
 +
GET /amigos
 +
GET /amigos/marta
 +
 +
</syntaxhighlight>
 +
 +
De hecho, encontrarás que estos dos segmentos son todo lo que tendrías que haber necesitado siempre. Pero podemos profundizar un poco más en la potencia de HTTP para indicar cómo queremos que el servidor responda a esas peticiones. Veamos:
 +
 +
Cada petición HTTP especifica un método, o un verbo, en sus encabezados. Generalmente te sonarán un par de ellos como GET y POST.
 +
 +
Por defecto el verbo utilizado cuando accedemos o vemos una página web es '''GET'''.
 +
 +
Para cualquier URI dada, podemos referenciar hasta 4 tipos diferentes de métodos: '''GET, POST, PUT, PATCH y DELETE'''.
 +
<syntaxhighlight lang='php'>
 +
GET /amigos
 +
POST /amigos
 +
PUT /amigos
 +
DELETE /amigos
 +
 +
</syntaxhighlight>
 +
 +
Esencialmente, estos verbos HTTP indican al servidor que hacer con los datos especificados en la URI. Una forma fácil de asociar estos verbos a las acciones realizadas, es comparándolo con '''CRUD''' (Create-Read-Update-Delete).
 +
<syntaxhighlight lang='php'>
 +
GET => READ
 +
POST => CREATE
 +
PUT => UPDATE
 +
DELETE => DELETE
 +
 +
 +
</syntaxhighlight>
 +
 +
Anteriormente hemos dicho que GET es el método utilizado por defecto, pero también te debería sonar POST. Cuando enviamos datos desde un formulario al servidor, solemos utilizar el método POST. Por ejemplo si quisiéramos añadir nuevos Tweets a nuestra base de datos, el formulario debería hacer un POST de los tweets POST /tweets, en lugar de hacer /tweets/añadirNuevoTweet.php.
 +
 +
Ejemplos de URIs que son no RESTful y que no se recomienda utilizar:
 +
<syntaxhighlight lang='php'>
 +
/tweets/añadirNuevoTweet.php
 +
/amigos/borrarAmigoPorNombre.php
 +
/contactos/actualizarContacto.php
 +
</syntaxhighlight>
 +
 +
Ejemplos de URIs que son RESTful y que serían un buen ejemplo:
 +
<syntaxhighlight lang='php'>
 +
GET /tickets/12/messages - Devuelve una lista de mensajes para el ticket #12
 +
GET /tickets/12/messages/5 - Devuelve el mensaje #5 para el ticket #12
 +
POST /tickets/12/messages - Crea un nuevo mensaje en el ticket #12
 +
PUT /tickets/12/messages/5 – Actualiza el mensaje #5 para el ticket #12
 +
PATCH /tickets/12/messages/5 - Actualiza parcialmente el mensaje #5 para el ticket #12
 +
DELETE /tickets/12/messages/5 - Borra el mensaje #5 para el ticket #12
 +
</syntaxhighlight>
 +
 +
'''¿Pero entonces, cuáles serían las URIs correctas para presentar un formulario al usuario, con el objetivo de añadir o editar un recurso?'''
 +
 +
En situaciones como esta, tiene más sentido añadir URIs como:
 +
<syntaxhighlight lang='bash'>
 +
GET /amigos/nuevo
 +
GET /amigos/marta/editar
 +
</syntaxhighlight>
 +
 +
La primera parte de la trayectoria /amigos/nuevo, debería presentar un formulario al usuario para añadir un amigo nuevo. Inmediatamente después de enviar el formulario, debería usarse una solicitud POST, ya que estamos añadiendo un nuevo amigo.
 +
 +
Para el segundo caso /amigos/marta/editar, este formulario debería editar un usuario existente en la base de datos. Cuando actualizamos los datos de un recurso, se debería utilizar una solicitud PUT.
 +
 +
'''Más información de cómo nombrar las URI en una API REST:'''
 +
 +
http://www.restapitutorial.com/lessons/restfulresourcenaming.html
 +
 +
'''Otro libro recomendable sobre RESTful''':
 +
http://restcookbook.com/
 +
 +
== Verbos disponibles en REST ==
 +
 +
Antes de seguir adelante con ejemplos concretos, vamos a revisar un poco más los verbos utilizados en las peticiones a una API REST.
 +
 +
=== GET (Recuperar) ===
 +
 +
GET es el método HTTP utilizado por defecto en las peticiones web. Una advertencia a tener en cuenta es que deberíamos utilizar GET, para hacer peticiones sólo de lectura, y deberíamos obtener siempre el mismo tipo de resultado, independientemente de las veces que sea llamado ese método.
 +
 +
Como programador puedes hacer lo que quieras cuando se hace una llamada a las rutas en la URI, pero una buena práctica es seguir las reglas generales para diseñar una API REST correctamente.
 +
 +
=== POST (Crear) ===
 +
 +
El segundo método que te resultará familiar es POST. Se utilizará para indicar que vamos a crear un subconjunto del recurso especificado, o también si estamos actualizando uno o más subconjuntos del recurso especificado.
 +
 +
Por ejemplo vamos a crear un recurso nuevo por ejemplo enviando un nuevo usuario para darlo de alta, entonces lo haremos a la URL /amigos
 +
 +
<syntaxhighlight lang='bash'>
 +
  POST /amigos
 +
</syntaxhighlight>
 +
 +
=== PUT (Actualizar) ===
 +
 +
Utiliza PUT cuando quieras actualizar un recurso específico a través de su localizador en la URL.
 +
 +
Por ejemplo si un artículo está en la URL
 +
http://miweb.local/api/articulos/1333, podemos actualizar ese recurso haciendo
 +
 +
<syntaxhighlight lang='bash'>
 +
    PUT /api/articulos/1333
 +
</syntaxhighlight>
 +
 +
Si no conocemos la dirección del recurso actual, for ejemplo para añadir un nuevo artículo, entonces utilizaríamos la acción POST. Por ejemplo.
 +
 +
<syntaxhighlight lang='bash'>
 +
    POST /api/articulos
 +
</syntaxhighlight>
 +
 +
=== DELETE (Borrado) ===
 +
 +
Por último DELETE debería se usado cuando queremos borrar el recurso especificado en la URI. Por ejemplo si ya no somos más amigos de macarena, siguiendo los principios de REST, podríamos borrarla usando una petición delete a la URI:
 +
 +
<syntaxhighlight lang='bash'>
 +
  DELETE /amigos/macarena
 +
</syntaxhighlight>
 +
 +
=== PATCH (Actualizaciones parciales) ===
 +
Una solicitud de tipo PATCH  se utiliza para realizar una actualización parcial de un recurso, aunque este tipo de acción no está siendo demasiado bien aceptada por los navegadores, por que no lo veremos en detalle.
 +
 +
== Buenas prácticas en el diseño de una API REST ==
 +
 +
Consulta la siguiente dirección dónde se muestran guías y buenas prácticas para la creación de una API REST para nuestra aplicación:
 +
 +
http://elbauldelprogramador.com/buenas-practicas-para-el-diseno-de-una-api-restful-pragmatica/
 +
 +
http://restcookbook.com/
 +
 +
== Creación de una RESTFUL API o API REST ==
 +
 +
Para crear una API REST o RESTFUL API (en inglés) en php podremos hacerlo utilizando un fichero .htaccess dónde programamos todos los tipos de URI's que gestionaremos en la API o bien utilizando un framework que nos facilite dicha programación.
 +
 +
Veremos para ello el Slim micro Framework, que es bastante sencillo y nos facilita muchísimo este tipo de creación, con lo que podremos crear una API REST para cualquier aplicación que ya tengamos programada de forma muy sencilla.
 +
 +
== Slim framework ==
 +
 +
Slim framwework es un '''micro framework''' para PHP que nos permite escribir rápidamente aplicaciones web y APIs.
 +
 +
Para comenzar a utilizar frameworks y aprender MVC (Modelo Vista Controlador) es muy recomendable ya que se pueden hacer aplicaciones muy interesantes con muy poco código. No tiene la potencia de otros frameworks de PHP como Laravel, Code Igniter, etc.. pero hace bastante bien su trabajo.
 +
 +
Página web oficial: http://www.slimframework.com/
 +
 +
Documentación del framework: http://docs.slimframework.com/
 +
 +
 +
=== Características de Slim framework ===
 +
 +
* Creador de rutas bastante potente
 +
** Soporta métodos HTTP standard y personalizados.
 +
** Parámetros de ruta con comodines y condiciones.
 +
** Redirecciones de rutas, paros y saltos.
 +
* Renderizado de plantillas y vistas personalizadas.
 +
* Mensajes Flash.
 +
* Encriptación segura de cookies con AES-256.
 +
* Caché HTTP.
 +
* Logging de accesos personalizado.
 +
* Gestión de errores.
 +
* Configuración sencilla.
 +
 +
=== Requerimientos ===
 +
 +
Es necesario tener instalado PHP 5.3.0 o superior.
 +
 +
=== Descarga de Slim framework ===
 +
 +
El framework Slim se puede descargar desde Github en:
 +
https://github.com/codeguy/Slim/zipball/master
 +
 +
=== Instalación ===
 +
 +
Para su instalación simplemente se descomprime el .zip en la ruta dónde queramos dar servicio con este framework y lo único que nos interesa de ese zip es la '''carpeta Slim''' y el fichero '''.htaccess''' incluído en la carpeta principal.
 +
 +
El fichero '''index.php''' es un ejemplo interesante que estaría bien tenerlo para poder programar nuestra aplicación.
 +
 +
=== Creación de una API REST con Slim framework ===
 +
 +
A continuación se muestra el código fuente de un ejemplo sencillo de creación de una API REST con todas las operaciones disponibles en REST:
 +
 +
Fichero '''index.php''':
 +
 +
<syntaxhighlight lang="php">
 +
 +
<?php
 +
// Activamos las sesiones para el funcionamiento de flash['']
 +
@session_start();
 +
 +
require 'Slim/Slim.php';
 +
// El framework Slim tiene definido un namespace llamado Slim
 +
// Por eso aparece \Slim\ antes del nombre de la clase.
 +
\Slim\Slim::registerAutoloader();
 +
 +
// Creamos la aplicación.
 +
$app = new \Slim\Slim();
 +
 +
// Configuramos la aplicación. http://docs.slimframework.com/#Configuration-Overview
 +
// Se puede hacer en la línea anterior con:
 +
// $app = new \Slim\Slim(array('templates.path' => 'vistas'));
 +
// O bien con $app->config();
 +
$app->config(array(
 +
    'templates.path' => 'vistas',
 +
));
 +
 +
// Indicamos el tipo de contenido y condificación que devolvemos desde el framework Slim.
 +
$app->contentType('text/html; charset=utf-8');
 +
 +
// Definimos conexion de la base de datos.
 +
// Lo haremos utilizando PDO con el driver mysql.
 +
define('BD_SERVIDOR', 'localhost');
 +
define('BD_NOMBRE', 'c2base2');
 +
define('BD_USUARIO', 'c2mysql');
 +
define('BD_PASSWORD', 'abc123.');
 +
 +
// Hacemos la conexión a la base de datos con PDO.
 +
// Para activar las collations en UTF8 podemos hacerlo al crear la conexión por PDO
 +
// o bien una vez hecha la conexión con
 +
// $db->exec("set names utf8");
 +
$db = new PDO('mysql:host=' . BD_SERVIDOR . ';dbname=' . BD_NOMBRE . ';charset=utf8', BD_USUARIO, BD_PASSWORD);
 +
 +
////////////////////////////////////////////
 +
// Definición de rutas en la aplicación:
 +
// Ruta por defecto de la aplicación /
 +
////////////////////////////////////////////
 +
 +
$app->get('/', function() {
 +
            echo "Pagina de gestión API REST de mi aplicación.";
 +
        });
 +
 +
// Cuando accedamos por get a la ruta /usuarios ejecutará lo siguiente:
 +
$app->get('/usuarios', function() use($db) {
 +
            // Si necesitamos acceder a alguna variable global en el framework
 +
            // Tenemos que pasarla con use() en la cabecera de la función. Ejemplo: use($db)
 +
            // Va a devolver un objeto JSON con los datos de usuarios.
 +
            // Preparamos la consulta a la tabla.
 +
            $consulta = $db->prepare("select * from soporte_usuarios");
 +
            $consulta->execute();
 +
            // Almacenamos los resultados en un array asociativo.
 +
            $resultados = $consulta->fetchAll(PDO::FETCH_ASSOC);
 +
            // Devolvemos ese array asociativo como un string JSON.
 +
            echo json_encode($resultados);
 +
        });
 +
 +
 +
// Accedemos por get a /usuarios/ pasando un id de usuario.
 +
// Por ejemplo /usuarios/veiga
 +
// Ruta /usuarios/id
 +
// Los parámetros en la url se definen con :parametro
 +
// El valor del parámetro :idusuario se pasará a la función de callback como argumento
 +
$app->get('/usuarios/:idusuario', function($usuarioID) use($db) {
 +
            // Va a devolver un objeto JSON con los datos de usuarios.
 +
            // Preparamos la consulta a la tabla.
 +
            // En PDO los parámetros para las consultas se pasan con :nombreparametro (casualmente
 +
// coincide con el método usado por Slim).
 +
// No confundir con el parámetro :idusuario que si queremos usarlo tendríamos
 +
// que hacerlo con la variable $usuarioID
 +
            $consulta = $db->prepare("select * from soporte_usuarios where idusuario=:param1");
 +
 +
            // En el execute es dónde asociamos el :param1 con el valor que le toque.
 +
            $consulta->execute(array(':param1' => $usuarioID));
 +
 +
            // Almacenamos los resultados en un array asociativo.
 +
            $resultados = $consulta->fetchAll(PDO::FETCH_ASSOC);
 +
 +
            // Devolvemos ese array asociativo como un string JSON.
 +
            echo json_encode($resultados);
 +
        });
 +
 +
// Alta de usuarios en la API REST
 +
$app->post('/usuarios',function() use($db,$app) {
 +
    // Para acceder a los datos recibidos del formulario
 +
    $datosform=$app->request;
 +
   
 +
    // Los datos serán accesibles de esta forma:
 +
    // $datosform->post('apellidos')
 +
   
 +
    // Preparamos la consulta de insert.
 +
    $consulta=$db->prepare("insert into soporte_usuarios(idusuario,nombre,apellidos,email)
 +
values (:idusuario,:nombre,:apellidos,:email)");
 +
   
 +
    $estado=$consulta->execute(
 +
            array(
 +
                ':idusuario'=> $datosform->post('idusuario'),
 +
                ':nombre'=> $datosform->post('nombre'),
 +
                ':apellidos'=> $datosform->post('apellidos'),
 +
                ':email'=> $datosform->post('email')
 +
                )
 +
            );
 +
    if ($estado)
 +
        echo json_encode(array('estado'=>true,'mensaje'=>'Datos insertados correctamente.'));
 +
    else
 +
        echo json_encode(array('estado'=>false,'mensaje'=>'Error al insertar datos en la tabla.'));
 +
});
 +
 +
// Programamos la ruta de borrado en la API REST (DELETE)
 +
$app->delete('/usuarios/:idusuario',function($idusuario) use($db)
 +
{
 +
  $consulta=$db->prepare("delete from soporte_usuarios where idusuario=:id");
 +
 
 +
  $consulta->execute(array(':id'=>$idusuario));
 +
 
 +
if ($consulta->rowCount() == 1)
 +
  echo json_encode(array('estado'=>true,'mensaje'=>'El usuario '.$idusuario.' ha sido borrado correctamente.'));
 +
else
 +
  echo json_encode(array('estado'=>false,'mensaje'=>'ERROR: ese registro no se ha encontrado en la tabla.'));
 +
   
 +
});
 +
 +
 +
// Actualización de datos de usuario (PUT)
 +
$app->put('/usuarios/:idusuario',function($idusuario) use($db,$app) {
 +
    // Para acceder a los datos recibidos del formulario
 +
    $datosform=$app->request;
 +
   
 +
    // Los datos serán accesibles de esta forma:
 +
    // $datosform->post('apellidos')
 +
   
 +
    // Preparamos la consulta de update.
 +
    $consulta=$db->prepare("update soporte_usuarios set nombre=:nombre, apellidos=:apellidos, email=:email
 +
where idusuario=:idusuario");
 +
   
 +
    $estado=$consulta->execute(
 +
            array(
 +
                ':idusuario'=>$idusuario,
 +
                ':nombre'=> $datosform->post('nombre'),
 +
                ':apellidos'=> $datosform->post('apellidos'),
 +
                ':email'=> $datosform->post('email')
 +
                )
 +
            );
 +
   
 +
    // Si se han modificado datos...
 +
    if ($consulta->rowCount()==1)
 +
      echo json_encode(array('estado'=>true,'mensaje'=>'Datos actualizados correctamente.'));
 +
    else
 +
      echo json_encode(array('estado'=>false,'mensaje'=>'Error al actualizar datos, datos
 +
no modificados o registro no encontrado.'));
 +
});
 +
 +
 +
 +
 +
 +
//////////////////////////////////////////////////////////////////////////////////////////////////
 +
// A PARTIR DE AQUÍ ES UN EJEMPLO DE USO DE SLIM FRAMEWORK PARA HACER PARTES DE UNA APLICACIÓN.
 +
//////////////////////////////////////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////////////////
 +
//
 +
// EJEMPLO DE USO DEL SLIM FRAMEWORK PARA GENERAR UNA APLICACIÓN.
 +
//
 +
//
 +
//
 +
// Ésto no formaría parte de la API REST. Ésto sería un ejemplo de aplicación
 +
// que podemos generar con el framework Slim.
 +
// Aquí se muestra un ejemplo de como se generaría una página utilizando vistas.
 +
////////////////////////////////////////////////////////////////////////////
 +
$app->get('/listadousuarios', function() use($db, $app) {
 +
            // Va a devolver un objeto JSON con los datos de usuarios.
 +
            // Preparamos la consulta a la tabla.
 +
            $consulta = $db->prepare("select * from soporte_usuarios");
 +
            // Ejecutamos la consulta (si fuera necesario se le pasan parámetros).
 +
            $consulta->execute();
 +
 +
            // Ejemplo sencillo de paso de variables a una plantilla.
 +
            /*
 +
              $app->render('miplantilla.php', array(
 +
              'name' => 'John',
 +
              'email' => '[email blocked]',
 +
              'active' => true
 +
              )
 +
              );
 +
            */
 +
 +
            // Desde dentro de la vista accederemos directamente a $resultados para gestionar su contenido.
 +
            $app->render('listadousuarios.php', array(
 +
                'resultados' => $consulta->fetchAll(PDO::FETCH_ASSOC)
 +
                    )
 +
            );
 +
        });
 +
 +
 +
       
 +
// Cuando accedamos a /nuevousuario se mostrará un formulario de alta.
 +
$app->get('/nuevousuario',function() use($app)
 +
{
 +
    $app->render('nuevousuario.php');
 +
})->name('altausuarios');
 +
 +
 +
// Ruta que recibe los datos del formulario
 +
$app->post('/nuevousuario',function() use($app,$db)
 +
{
 +
      // Para acceder a los datos recibidos del formulario
 +
    $datosform=$app->request;
 +
   
 +
    // Los datos serán accesibles de esta forma:
 +
    // $datosform->post('apellidos')
 +
   
 +
    // Preparamos la consulta de insert.
 +
    $consulta=$db->prepare("insert into soporte_usuarios(idusuario,nombre,apellidos,email)
 +
values (:idusuario,:nombre,:apellidos,:email)");
 +
   
 +
    $estado=$consulta->execute(
 +
            array(
 +
                ':idusuario'=> $datosform->post('idusuario'),
 +
                ':nombre'=> $datosform->post('nombre'),
 +
                ':apellidos'=> $datosform->post('apellidos'),
 +
                ':email'=> $datosform->post('email')
 +
                )
 +
            );
 +
   
 +
    if ($estado)
 +
        $app->flash('message','Usuario insertado correctamente.');
 +
    else
 +
        $app->flash('error','Se ha producido un error al guardar datos.');
 +
   
 +
    // Redireccionamos al formulario original para mostrar
 +
    // los mensajes Flash.,
 +
    $app->redirect('nuevousuario');
 +
   
 +
    // Otra forma de hacerlo es:
 +
    // $app->redirect($app->urlFor('altausuarios'));
 +
   
 +
   
 +
});
 +
 +
 +
 +
// Otro ejemplo de aplicación en:
 +
// http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/
 +
 +
 +
///////////////////////////////////////////////////////////////////////////////////////////////////////
 +
// Al final de la aplicación terminamos con $app->run();
 +
///////////////////////////////////////////////////////////////////////////////////////////////////////
 +
 +
$app->run();
 +
?>
 +
 +
</syntaxhighlight>
 +
 +
Fichero cliente para hacer peticiones REST con jQuery: '''formulario.html''':
 +
 +
<syntaxhighlight lang="html4strict">
 +
 +
<!doctype html>
 +
<html lang="es">
 +
    <head>
 +
        <meta charset="utf-8">
 +
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
 +
        <title>Formulario peticiones REST</title>
 +
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
 +
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
 +
    </head>
 +
    <body>
 +
        <script>
 +
            $(document).ready(function()
 +
            {
 +
                $.ajaxSetup({cache: false});
 +
 +
                // Alta de usuarios.
 +
                $("#alta").click(function()
 +
                {
 +
                    $.post("usuarios",$("#formulario").serialize(),function(resultados)
 +
                    {
 +
                      resultados=$.parseJSON(resultados);
 +
                      mensajes(resultados.estado,resultados.mensaje);
 +
                    });
 +
                });
 +
                 
 +
                // Borrado de usuarios.
 +
                $("#borrado").click(function()
 +
                {
 +
                    if ($("#idusuario").val()!="")
 +
                        $.ajax(
 +
                            {
 +
                                type: 'DELETE',
 +
                                url: 'usuarios/'+$("#idusuario").val(),
 +
                                cache: false,
 +
                                dataType: "json",
 +
                                success: function(resultados,textStatus,jqXHR)
 +
                                {
 +
                                    // No tenemos q convertir el string JSON
 +
                                    // por que ya lo convierte a objeto
 +
                                    // automaticamente al indicarlo en dataType
 +
                                      mensajes(resultados.estado,resultados.mensaje);                                   
 +
                                },
 +
                                error: function(jqXHR, textStatus, errorThrown)
 +
                                {
 +
                                      alert(textStatus);
 +
                              }
 +
                            }); // Fin peticion $.ajax.
 +
                }); // Fin click borrado
 +
               
 +
               
 +
               
 +
                // Actualización de usuarios.
 +
                $("#actualizacion").click(function()
 +
                {
 +
                    if ($("#idusuario").val()!="")
 +
                        $.ajax(
 +
                            {
 +
                                type: 'PUT',
 +
                                url: 'usuarios/'+$("#idusuario").val(),
 +
                                cache: false,
 +
                                data: $("#formulario").serialize(),
 +
                                dataType: "json",
 +
                                success: function(resultados,textStatus,jqXHR)
 +
                                {
 +
                                    // No tenemos q convertir el string JSON
 +
                                    // por que ya lo convierte a objeto
 +
                                    // automaticamente al indicarlo en dataType
 +
                                      mensajes(resultados.estado,resultados.mensaje);                                   
 +
                                },
 +
                                error: function(jqXHR, textStatus, errorThrown)
 +
                                {
 +
                                      alert(textStatus);
 +
                              }
 +
                            }); // Fin peticion $.ajax.
 +
                }); // Fin click borrado
 +
               
 +
 +
                function mensajes(estado, mensaje)
 +
                {
 +
                    if (estado)
 +
                        $("#mensajes").hide().html('<span class="label label-success">' +
 +
mensaje + '</span>').fadeIn(500).delay(1000).fadeOut(1500);
 +
                    else
 +
                        $("#mensajes").hide().html('<span class="label label-danger">' +
 +
mensaje + '</span>').fadeIn(500).delay(1000).fadeOut(1500);
 +
                }
 +
            });
 +
        </script>
 +
 +
<div class="container">
 +
<form id="formulario" role="form" style="margin:0 auto;max-width:600px;padding:15px;">
 +
<legend>Prueba de peticiones REST: POST, PUT y DELETE</legend>
 +
<div class="form-group">
 +
<label for="idusuario">ID Usuario</label>
 +
<input type="text" class="form-control" id="idusuario" name="idusuario" placeholder="Introduzca id Usuario">
 +
<label for="nombre">Nombre</label>
 +
<input type="text" class="form-control" id="nombre" name="nombre" placeholder="Introduzca nombre">
 +
<label for="apellidos">Apellidos</label>
 +
<input type="text" class="form-control" id="apellidos" name="apellidos" placeholder="Introduzca apellidos">
 +
<label for="email">E-mail</label>
 +
<input type="text" class="form-control" id="email" name="email" placeholder="Introduzca e-mail">
 +
</div>
 +
<button type="button" class="btn btn-primary" id="alta">Alta de Usuario (POST)</button>
 +
<button type="button" class="btn btn-primary" id="actualizacion">Actualización de Datos de Usuario (PUT)</button>
 +
<br/>
 +
<button type="button" class="btn btn-primary" id="borrado">Borrado Usuario (DELETE)</button>
 +
<div id="mensajes"></div>
 +
</form>
 +
</div>
 +
 +
</body>
 +
</html>
 +
 +
</syntaxhighlight>
 +
 +
 +
'''Puedes descargarte los ficheros fuentes de ejemplo junto con Slim framework aqui''': [[Archivo: ejemplo_rest.zip]]
 +
 +
== Extensión Advanced REST Client de Google Chrome ==
 +
 +
En el ejemplo anterior hemos visto que para probar la API REST hemos hecho un formulario con peticiones AJAX utilizando las diferentes acciones disponibles.
 +
 +
Una forma más sencilla de comprobar si nuestra API REST funciona correctamente es instalando una extensión de Google Chrome llamada '''"Advanced REST Client"''' la cuál nos permite simular peticiones de cualquier tipo a la URL que le indiquemos.
 +
 +
Instalad la [https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo extensión para Google Chrome Advanced REST Client] desde aquí.
 +
 +
'''Video en Youtube de ejemplo de uso de Advanced REST Client''':
 +
 +
{{#ev:youtube|NHL_eUAHHLI}}
 +
 +
== Otros frameworks para PHP ==
 +
 +
Aquí tenéis una URL con enlaces a otros frameworks de PHP más potentes, pero a su vez con una curva de aprendizaje mayor:
 +
 +
http://www.genbetadev.com/frameworks/un-punado-de-frameworks-php-que-te-haran-la-vida-mas-simple
 +
 +
Mi recomendación particular es '''LARAVEL''':
 +
 +
* [http://laravel.com/ Página oficial del framework Laravel]
 +
* [https://laracasts.com/ Video tutoriales sobre Laravel]
 +
 +
 +
 +
--[[Usuario:Veiga|Veiga]] ([[Usuario discusión:Veiga|discusión]])

Última revisión de 02:46 5 mar 2015




Introducción a REST

REST al igual que otras tecnologías, como Git y CSS, requiere un poco de tiempo para su comprensión. En este breve manual nos centraremos en la filosofía que está detrás de REST(así como sus diferencias con SOAP), y en los aspectos prácticos. ¿Cómo podemos implementar REST hoy?

¿Que es es REST?

REST son las siglas de Representational State Transfer. Fue definido hace una década por Roy Fielding en su tesis doctoral, y proporciona una forma sencilla de interacción entre sistemas, la mayor parte de las veces a través de un navegador web y HTTP. Esta cohesión con HTTP viene también de que Roy es uno de los principales autores de HTTP.

REST es un estilo arquitectónico, un conjunto de convenciones para aplicaciones web y servicios web, que se centra principalmente en la manipulación de recursos a través de especificaciones HTTP. Podemos decir que REST es una interfaz web estándar y simple que nos permite interactuar con servicios web de una manera muy cómoda.

Gracias a REST la web ha disfrutado de escalabilidad como resultado de una serie de diseños fundamentales clave:

  • Un protocolo cliente/servidor sin estado: cada mensaje HTTP contiene toda la información necesaria para comprender la petición. Como resultado, ni el cliente ni el servidor necesitan recordar ningún estado de las comunicaciones entre mensajes. Sin embargo, en la práctica, muchas aplicaciones basadas en HTTP utilizan cookies y otros mecanismos para mantener el estado de la sesión (algunas de estas prácticas, como la reescritura de URLs, no son permitidas por REST).
  • Un conjunto de operaciones bien definidas que se aplican a todos los recursos de información: HTTP en sí define un conjunto pequeño de operaciones, las más importantes son POST, GET, PUT y DELETE. Con frecuencia estas operaciones se equiparan a las operaciones CRUD que se requieren para la persistencia de datos, aunque POST no encaja exactamente en este esquema.
  • Una sintaxis universal para identificar los recursos. En un sistema REST, cada recurso es direccionable únicamente a través de su URI.
  • El uso de hipermedios, tanto para la información de la aplicación como para las transiciones de estado de la aplicación: la representación de este estado en un sistema REST son típicamente HTML o XML. Como resultado de esto, es posible navegar de un recurso REST a muchos otros, simplemente siguiendo enlaces sin requerir el uso de registros u otra infraestructura adicional.


Vamos a ver primero lo que son las URIs. Una URI es esencialmente un identificador de un recurso. Veamos el siguiente ejemplo:

GET /amigos

Podríamos llamar a esto un recurso. Cuando esta ruta es llamada, siguiendo los patrones REST, se obtendrán todos los amigos (generalmente de una base de datos), y se mostrarán en pantalla o se devolverán en un formato determinado a quien lo solicite.

Pero, cómo haremos si queremos especificar un amigo en particular?.

GET /amigos/marta


Como se puede ver es fácilmente comprensible. Esa es una de las claves de la arquitectura RESTful. Permite el uso de URIs que son fácilmente comprensibles por los humanos y las máquinas.

Piensa en un recurso como un nombre en plural. Contactos, estados, usuarios, fotos --- todos éstos serían elecciones perfectas.

Hasta ahora, hemos visto como identificar a una colección y a elementos individuales en esa colección:

GET /amigos
GET /amigos/marta

De hecho, encontrarás que estos dos segmentos son todo lo que tendrías que haber necesitado siempre. Pero podemos profundizar un poco más en la potencia de HTTP para indicar cómo queremos que el servidor responda a esas peticiones. Veamos:

Cada petición HTTP especifica un método, o un verbo, en sus encabezados. Generalmente te sonarán un par de ellos como GET y POST.

Por defecto el verbo utilizado cuando accedemos o vemos una página web es GET.

Para cualquier URI dada, podemos referenciar hasta 4 tipos diferentes de métodos: GET, POST, PUT, PATCH y DELETE.

GET /amigos
POST /amigos
PUT /amigos
DELETE /amigos

Esencialmente, estos verbos HTTP indican al servidor que hacer con los datos especificados en la URI. Una forma fácil de asociar estos verbos a las acciones realizadas, es comparándolo con CRUD (Create-Read-Update-Delete).

GET => READ
POST => CREATE
PUT => UPDATE
DELETE => DELETE

Anteriormente hemos dicho que GET es el método utilizado por defecto, pero también te debería sonar POST. Cuando enviamos datos desde un formulario al servidor, solemos utilizar el método POST. Por ejemplo si quisiéramos añadir nuevos Tweets a nuestra base de datos, el formulario debería hacer un POST de los tweets POST /tweets, en lugar de hacer /tweets/añadirNuevoTweet.php.

Ejemplos de URIs que son no RESTful y que no se recomienda utilizar:

 /tweets/añadirNuevoTweet.php
 /amigos/borrarAmigoPorNombre.php
 /contactos/actualizarContacto.php

Ejemplos de URIs que son RESTful y que serían un buen ejemplo:

 GET /tickets/12/messages - Devuelve una lista de mensajes para el ticket #12
 GET /tickets/12/messages/5 - Devuelve el mensaje #5 para el ticket #12
 POST /tickets/12/messages - Crea un nuevo mensaje en el ticket #12
 PUT /tickets/12/messages/5 – Actualiza el mensaje #5 para el ticket #12
 PATCH /tickets/12/messages/5 - Actualiza parcialmente el mensaje #5 para el ticket #12
 DELETE /tickets/12/messages/5 - Borra el mensaje #5 para el ticket #12

¿Pero entonces, cuáles serían las URIs correctas para presentar un formulario al usuario, con el objetivo de añadir o editar un recurso?

En situaciones como esta, tiene más sentido añadir URIs como:

GET /amigos/nuevo
GET /amigos/marta/editar

La primera parte de la trayectoria /amigos/nuevo, debería presentar un formulario al usuario para añadir un amigo nuevo. Inmediatamente después de enviar el formulario, debería usarse una solicitud POST, ya que estamos añadiendo un nuevo amigo.

Para el segundo caso /amigos/marta/editar, este formulario debería editar un usuario existente en la base de datos. Cuando actualizamos los datos de un recurso, se debería utilizar una solicitud PUT.

Más información de cómo nombrar las URI en una API REST:

http://www.restapitutorial.com/lessons/restfulresourcenaming.html

Otro libro recomendable sobre RESTful: http://restcookbook.com/

Verbos disponibles en REST

Antes de seguir adelante con ejemplos concretos, vamos a revisar un poco más los verbos utilizados en las peticiones a una API REST.

GET (Recuperar)

GET es el método HTTP utilizado por defecto en las peticiones web. Una advertencia a tener en cuenta es que deberíamos utilizar GET, para hacer peticiones sólo de lectura, y deberíamos obtener siempre el mismo tipo de resultado, independientemente de las veces que sea llamado ese método.

Como programador puedes hacer lo que quieras cuando se hace una llamada a las rutas en la URI, pero una buena práctica es seguir las reglas generales para diseñar una API REST correctamente.

POST (Crear)

El segundo método que te resultará familiar es POST. Se utilizará para indicar que vamos a crear un subconjunto del recurso especificado, o también si estamos actualizando uno o más subconjuntos del recurso especificado.

Por ejemplo vamos a crear un recurso nuevo por ejemplo enviando un nuevo usuario para darlo de alta, entonces lo haremos a la URL /amigos

  POST /amigos

PUT (Actualizar)

Utiliza PUT cuando quieras actualizar un recurso específico a través de su localizador en la URL.

Por ejemplo si un artículo está en la URL http://miweb.local/api/articulos/1333, podemos actualizar ese recurso haciendo

    PUT /api/articulos/1333

Si no conocemos la dirección del recurso actual, for ejemplo para añadir un nuevo artículo, entonces utilizaríamos la acción POST. Por ejemplo.

    POST /api/articulos

DELETE (Borrado)

Por último DELETE debería se usado cuando queremos borrar el recurso especificado en la URI. Por ejemplo si ya no somos más amigos de macarena, siguiendo los principios de REST, podríamos borrarla usando una petición delete a la URI:

  DELETE /amigos/macarena

PATCH (Actualizaciones parciales)

Una solicitud de tipo PATCH se utiliza para realizar una actualización parcial de un recurso, aunque este tipo de acción no está siendo demasiado bien aceptada por los navegadores, por que no lo veremos en detalle.

Buenas prácticas en el diseño de una API REST

Consulta la siguiente dirección dónde se muestran guías y buenas prácticas para la creación de una API REST para nuestra aplicación:

http://elbauldelprogramador.com/buenas-practicas-para-el-diseno-de-una-api-restful-pragmatica/

http://restcookbook.com/

Creación de una RESTFUL API o API REST

Para crear una API REST o RESTFUL API (en inglés) en php podremos hacerlo utilizando un fichero .htaccess dónde programamos todos los tipos de URI's que gestionaremos en la API o bien utilizando un framework que nos facilite dicha programación.

Veremos para ello el Slim micro Framework, que es bastante sencillo y nos facilita muchísimo este tipo de creación, con lo que podremos crear una API REST para cualquier aplicación que ya tengamos programada de forma muy sencilla.

Slim framework

Slim framwework es un micro framework para PHP que nos permite escribir rápidamente aplicaciones web y APIs.

Para comenzar a utilizar frameworks y aprender MVC (Modelo Vista Controlador) es muy recomendable ya que se pueden hacer aplicaciones muy interesantes con muy poco código. No tiene la potencia de otros frameworks de PHP como Laravel, Code Igniter, etc.. pero hace bastante bien su trabajo.

Página web oficial: http://www.slimframework.com/

Documentación del framework: http://docs.slimframework.com/


Características de Slim framework

  • Creador de rutas bastante potente
    • Soporta métodos HTTP standard y personalizados.
    • Parámetros de ruta con comodines y condiciones.
    • Redirecciones de rutas, paros y saltos.
  • Renderizado de plantillas y vistas personalizadas.
  • Mensajes Flash.
  • Encriptación segura de cookies con AES-256.
  • Caché HTTP.
  • Logging de accesos personalizado.
  • Gestión de errores.
  • Configuración sencilla.

Requerimientos

Es necesario tener instalado PHP 5.3.0 o superior.

Descarga de Slim framework

El framework Slim se puede descargar desde Github en: https://github.com/codeguy/Slim/zipball/master

Instalación

Para su instalación simplemente se descomprime el .zip en la ruta dónde queramos dar servicio con este framework y lo único que nos interesa de ese zip es la carpeta Slim y el fichero .htaccess incluído en la carpeta principal.

El fichero index.php es un ejemplo interesante que estaría bien tenerlo para poder programar nuestra aplicación.

Creación de una API REST con Slim framework

A continuación se muestra el código fuente de un ejemplo sencillo de creación de una API REST con todas las operaciones disponibles en REST:

Fichero index.php:

<?php
// Activamos las sesiones para el funcionamiento de flash['']
@session_start();
 
require 'Slim/Slim.php';
// El framework Slim tiene definido un namespace llamado Slim
// Por eso aparece \Slim\ antes del nombre de la clase.
\Slim\Slim::registerAutoloader();
 
// Creamos la aplicación.
$app = new \Slim\Slim();
 
// Configuramos la aplicación. http://docs.slimframework.com/#Configuration-Overview
// Se puede hacer en la línea anterior con:
// $app = new \Slim\Slim(array('templates.path' => 'vistas'));
// O bien con $app->config();
$app->config(array(
    'templates.path' => 'vistas',
));
 
// Indicamos el tipo de contenido y condificación que devolvemos desde el framework Slim.
$app->contentType('text/html; charset=utf-8');
 
// Definimos conexion de la base de datos.
// Lo haremos utilizando PDO con el driver mysql.
define('BD_SERVIDOR', 'localhost');
define('BD_NOMBRE', 'c2base2');
define('BD_USUARIO', 'c2mysql');
define('BD_PASSWORD', 'abc123.');
 
// Hacemos la conexión a la base de datos con PDO.
// Para activar las collations en UTF8 podemos hacerlo al crear la conexión por PDO
// o bien una vez hecha la conexión con
// $db->exec("set names utf8");
$db = new PDO('mysql:host=' . BD_SERVIDOR . ';dbname=' . BD_NOMBRE . ';charset=utf8', BD_USUARIO, BD_PASSWORD);
 
////////////////////////////////////////////
// Definición de rutas en la aplicación:
// Ruta por defecto de la aplicación /
////////////////////////////////////////////
 
$app->get('/', function() {
            echo "Pagina de gestión API REST de mi aplicación.";
        });
 
// Cuando accedamos por get a la ruta /usuarios ejecutará lo siguiente:
$app->get('/usuarios', function() use($db) {
            // Si necesitamos acceder a alguna variable global en el framework
            // Tenemos que pasarla con use() en la cabecera de la función. Ejemplo: use($db)
            // Va a devolver un objeto JSON con los datos de usuarios.
            // Preparamos la consulta a la tabla.
            $consulta = $db->prepare("select * from soporte_usuarios");
            $consulta->execute();
            // Almacenamos los resultados en un array asociativo.
            $resultados = $consulta->fetchAll(PDO::FETCH_ASSOC);
            // Devolvemos ese array asociativo como un string JSON.
            echo json_encode($resultados);
        });
 
 
// Accedemos por get a /usuarios/ pasando un id de usuario. 
// Por ejemplo /usuarios/veiga
// Ruta /usuarios/id
// Los parámetros en la url se definen con :parametro
// El valor del parámetro :idusuario se pasará a la función de callback como argumento
$app->get('/usuarios/:idusuario', function($usuarioID) use($db) {
            // Va a devolver un objeto JSON con los datos de usuarios.
            // Preparamos la consulta a la tabla.
            // En PDO los parámetros para las consultas se pasan con :nombreparametro (casualmente 
			// coincide con el método usado por Slim).
			// No confundir con el parámetro :idusuario que si queremos usarlo tendríamos 
			// que hacerlo con la variable $usuarioID
            $consulta = $db->prepare("select * from soporte_usuarios where idusuario=:param1");
 
            // En el execute es dónde asociamos el :param1 con el valor que le toque.
            $consulta->execute(array(':param1' => $usuarioID));
 
            // Almacenamos los resultados en un array asociativo.
            $resultados = $consulta->fetchAll(PDO::FETCH_ASSOC);
 
            // Devolvemos ese array asociativo como un string JSON.
            echo json_encode($resultados);
        });
 
// Alta de usuarios en la API REST
$app->post('/usuarios',function() use($db,$app) {
    // Para acceder a los datos recibidos del formulario
    $datosform=$app->request;
 
    // Los datos serán accesibles de esta forma:
    // $datosform->post('apellidos')
 
    // Preparamos la consulta de insert.
    $consulta=$db->prepare("insert into soporte_usuarios(idusuario,nombre,apellidos,email) 
					values (:idusuario,:nombre,:apellidos,:email)");
 
    $estado=$consulta->execute(
            array(
                ':idusuario'=> $datosform->post('idusuario'),
                ':nombre'=> $datosform->post('nombre'),
                ':apellidos'=> $datosform->post('apellidos'),
                ':email'=> $datosform->post('email')
                )
            );
    if ($estado)
        echo json_encode(array('estado'=>true,'mensaje'=>'Datos insertados correctamente.'));
    else
        echo json_encode(array('estado'=>false,'mensaje'=>'Error al insertar datos en la tabla.'));
});
 
// Programamos la ruta de borrado en la API REST (DELETE)
$app->delete('/usuarios/:idusuario',function($idusuario) use($db)
{
   $consulta=$db->prepare("delete from soporte_usuarios where idusuario=:id");
 
   $consulta->execute(array(':id'=>$idusuario));
 
if ($consulta->rowCount() == 1)
   echo json_encode(array('estado'=>true,'mensaje'=>'El usuario '.$idusuario.' ha sido borrado correctamente.'));
 else
   echo json_encode(array('estado'=>false,'mensaje'=>'ERROR: ese registro no se ha encontrado en la tabla.'));
 
});
 
 
// Actualización de datos de usuario (PUT)
$app->put('/usuarios/:idusuario',function($idusuario) use($db,$app) {
    // Para acceder a los datos recibidos del formulario
    $datosform=$app->request;
 
    // Los datos serán accesibles de esta forma:
    // $datosform->post('apellidos')
 
    // Preparamos la consulta de update.
    $consulta=$db->prepare("update soporte_usuarios set nombre=:nombre, apellidos=:apellidos, email=:email 
							where idusuario=:idusuario");
 
    $estado=$consulta->execute(
            array(
                ':idusuario'=>$idusuario,
                ':nombre'=> $datosform->post('nombre'),
                ':apellidos'=> $datosform->post('apellidos'),
                ':email'=> $datosform->post('email')
                )
            );
 
    // Si se han modificado datos...
    if ($consulta->rowCount()==1)
      echo json_encode(array('estado'=>true,'mensaje'=>'Datos actualizados correctamente.'));
    else
      echo json_encode(array('estado'=>false,'mensaje'=>'Error al actualizar datos, datos 
						no modificados o registro no encontrado.'));
});
 
 
 
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////
// A PARTIR DE AQUÍ ES UN EJEMPLO DE USO DE SLIM FRAMEWORK PARA HACER PARTES DE UNA APLICACIÓN.
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// EJEMPLO DE USO DEL SLIM FRAMEWORK PARA GENERAR UNA APLICACIÓN.
// 
// 
//
// Ésto no formaría parte de la API REST. Ésto sería un ejemplo de aplicación
// que podemos generar con el framework Slim.
// Aquí se muestra un ejemplo de como se generaría una página utilizando vistas.
////////////////////////////////////////////////////////////////////////////
$app->get('/listadousuarios', function() use($db, $app) {
            // Va a devolver un objeto JSON con los datos de usuarios.
            // Preparamos la consulta a la tabla.
            $consulta = $db->prepare("select * from soporte_usuarios");
            // Ejecutamos la consulta (si fuera necesario se le pasan parámetros).
            $consulta->execute();
 
            // Ejemplo sencillo de paso de variables a una plantilla.
            /*
              $app->render('miplantilla.php', array(
              'name' => 'John',
              'email' => '[email blocked]',
              'active' => true
              )
              );
             */
 
            // Desde dentro de la vista accederemos directamente a $resultados para gestionar su contenido.
            $app->render('listadousuarios.php', array(
                'resultados' => $consulta->fetchAll(PDO::FETCH_ASSOC)
                    )
            );
        });
 
 
 
// Cuando accedamos a /nuevousuario se mostrará un formulario de alta.
$app->get('/nuevousuario',function() use($app)
{
    $app->render('nuevousuario.php');
})->name('altausuarios');
 
 
// Ruta que recibe los datos del formulario
$app->post('/nuevousuario',function() use($app,$db)
{
      // Para acceder a los datos recibidos del formulario
    $datosform=$app->request;
 
    // Los datos serán accesibles de esta forma:
    // $datosform->post('apellidos')
 
    // Preparamos la consulta de insert.
    $consulta=$db->prepare("insert into soporte_usuarios(idusuario,nombre,apellidos,email)
				values (:idusuario,:nombre,:apellidos,:email)");
 
    $estado=$consulta->execute(
            array(
                ':idusuario'=> $datosform->post('idusuario'),
                ':nombre'=> $datosform->post('nombre'),
                ':apellidos'=> $datosform->post('apellidos'),
                ':email'=> $datosform->post('email')
                )
            );
 
    if ($estado)
        $app->flash('message','Usuario insertado correctamente.');
    else
        $app->flash('error','Se ha producido un error al guardar datos.');
 
    // Redireccionamos al formulario original para mostrar 
    // los mensajes Flash.,
    $app->redirect('nuevousuario');
 
    // Otra forma de hacerlo es:
    // $app->redirect($app->urlFor('altausuarios'));
 
 
});
 
 
 
// Otro ejemplo de aplicación en:
// http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Al final de la aplicación terminamos con $app->run();
///////////////////////////////////////////////////////////////////////////////////////////////////////
 
$app->run();
?>

Fichero cliente para hacer peticiones REST con jQuery: formulario.html:

<!doctype html>
<html lang="es">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Formulario peticiones REST</title>
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>	
    <body>
        <script>
            $(document).ready(function()
            {
                $.ajaxSetup({cache: false});
 
                // Alta de usuarios.
                $("#alta").click(function()
                {
                    $.post("usuarios",$("#formulario").serialize(),function(resultados)
                    {
                       resultados=$.parseJSON(resultados);
                       mensajes(resultados.estado,resultados.mensaje);
                    });
                });
 
                 // Borrado de usuarios.
                 $("#borrado").click(function()
                 {
                    if ($("#idusuario").val()!="")
                        $.ajax(
                            {
                                type: 'DELETE',
                                url: 'usuarios/'+$("#idusuario").val(),
                                cache: false,
                                dataType: "json",
                                success: function(resultados,textStatus,jqXHR)
                                {
                                    // No tenemos q convertir el string JSON
                                    // por que ya lo convierte a objeto
                                    // automaticamente al indicarlo en dataType
                                       mensajes(resultados.estado,resultados.mensaje);                                    
                                },
                                error: function(jqXHR, textStatus, errorThrown)
                                {
                                       alert(textStatus);
                               }
                            }); // Fin peticion $.ajax.
                 }); // Fin click borrado
 
 
 
                 // Actualización de usuarios.
                 $("#actualizacion").click(function()
                 {
                    if ($("#idusuario").val()!="")
                        $.ajax(
                            {
                                type: 'PUT',
                                url: 'usuarios/'+$("#idusuario").val(),
                                cache: false,
                                data: $("#formulario").serialize(),
                                dataType: "json",
                                success: function(resultados,textStatus,jqXHR)
                                {
                                    // No tenemos q convertir el string JSON
                                    // por que ya lo convierte a objeto
                                    // automaticamente al indicarlo en dataType
                                       mensajes(resultados.estado,resultados.mensaje);                                    
                                },
                                error: function(jqXHR, textStatus, errorThrown)
                                {
                                       alert(textStatus);
                               }
                            }); // Fin peticion $.ajax.
                 }); // Fin click borrado
 
 
                function mensajes(estado, mensaje)
                {
                    if (estado)
                        $("#mensajes").hide().html('<span class="label label-success">' +
						mensaje + '</span>').fadeIn(500).delay(1000).fadeOut(1500);
                    else
                        $("#mensajes").hide().html('<span class="label label-danger">' +
						mensaje + '</span>').fadeIn(500).delay(1000).fadeOut(1500);
                }
            });
        </script>
 
<div class="container">
<form id="formulario" role="form" style="margin:0 auto;max-width:600px;padding:15px;">
	<legend>Prueba de peticiones REST: POST, PUT y DELETE</legend>
	<div class="form-group">
	<label for="idusuario">ID Usuario</label>
	<input type="text" class="form-control" id="idusuario" name="idusuario" placeholder="Introduzca id Usuario">
	<label for="nombre">Nombre</label>
	<input type="text" class="form-control" id="nombre" name="nombre" placeholder="Introduzca nombre">
	<label for="apellidos">Apellidos</label>
	<input type="text" class="form-control" id="apellidos" name="apellidos" placeholder="Introduzca apellidos">
	<label for="email">E-mail</label>
	<input type="text" class="form-control" id="email" name="email" placeholder="Introduzca e-mail">
	</div>
	<button type="button" class="btn btn-primary" id="alta">Alta de Usuario (POST)</button> 
	<button type="button" class="btn btn-primary" id="actualizacion">Actualización de Datos de Usuario (PUT)</button>
<br/>
	<button type="button" class="btn btn-primary" id="borrado">Borrado Usuario (DELETE)</button>
	<div id="mensajes"></div>
</form>
</div>
 
</body>
</html>


Puedes descargarte los ficheros fuentes de ejemplo junto con Slim framework aqui: Archivo:Ejemplo rest.zip

Extensión Advanced REST Client de Google Chrome

En el ejemplo anterior hemos visto que para probar la API REST hemos hecho un formulario con peticiones AJAX utilizando las diferentes acciones disponibles.

Una forma más sencilla de comprobar si nuestra API REST funciona correctamente es instalando una extensión de Google Chrome llamada "Advanced REST Client" la cuál nos permite simular peticiones de cualquier tipo a la URL que le indiquemos.

Instalad la extensión para Google Chrome Advanced REST Client desde aquí.

Video en Youtube de ejemplo de uso de Advanced REST Client:

{{#ev:youtube|NHL_eUAHHLI}}

Otros frameworks para PHP

Aquí tenéis una URL con enlaces a otros frameworks de PHP más potentes, pero a su vez con una curva de aprendizaje mayor:

http://www.genbetadev.com/frameworks/un-punado-de-frameworks-php-que-te-haran-la-vida-mas-simple

Mi recomendación particular es LARAVEL:


--Veiga (discusión)