Como crear un RESTful Web Service en PHP (API Rest)



Ahora veremos cómo crear un RESTful web service (API) utilizando PHP y MySQL para consultar y guardar la información. Para que puedas probar este código debes tener instalado PHP y MySQL, si aún no lo tienes, puedes seguir estos pasos en donde explico como instalar PHP, apache y MySQL sobre Windows.

Contenido de este artículo:

Antes que nada, debes de tener claro que es RESTful, si aún tienes dudas, puedes leer este artículo en donde explico que es un RESTFul Web Service de forma muy sencilla.

Para este ejemplo vamos a asumir que tenemos un blog y necesitamos un servicio RESTful para acceder a los artículos y editarlos, entonces nuestro servicio va a realizar estas operaciones:

  • Listar todos los posts (artículos de un blog)
  • Mostrar un post
  • Agregar un post
  • Eliminar un post
  • Actualizar uno o más campos de un post

Preparar la base de datos

Vamos a utilizar una tabla llamada blog (de MySql) con estos campos:

Base de datos, para servicio RESTful

Lo más importante aquí, es que el campo id debe estar marcado para auto incremento y debe ser la llave primaria, puedes usar este SQL, para generala en tu computadora, en mi caso la base de datos se llama blog:

CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  `status` enum('draft','published') COLLATE utf8_spanish_ci NOT NULL DEFAULT 'draft',
  `content` text COLLATE utf8_spanish_ci NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

Código de PHP para el web service RESTful

Ahora vamos a crear 3 archivos de PHP

  • config.php: En este archivo se encuentra la configuración para la base de datos
  • utils.php: Funciones que hacen más fácil interactuar con la base de datos
  • post.php: El código propio del web service RESTful

Este es el archivo de configuración, debes asegurarte de que tiene todos los parámetros correctos para que pueda conectarse a tu base de datos

<?php
$db = [
    'host' => 'localhost',
    'username' => 'root',
    'password' => '',
    'db' => 'blog' //Cambiar al nombre de tu base de datos
];
?>

Ahora el archivo de utilidades:

<?php
  //Abrir conexion a la base de datos
  function connect($db)
  {
      try {
          $conn = new PDO("mysql:host={$db['host']};dbname={$db['db']};charset=utf8", $db['username'], $db['password']);
          // set the PDO error mode to exception
          $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
          return $conn;
      } catch (PDOException $exception) {
          exit($exception->getMessage());
      }
  }
 //Obtener parametros para updates
 function getParams($input)
 {
    $filterParams = [];
    foreach($input as $param => $value)
    {
            $filterParams[] = "$param=:$param";
    }
    return implode(", ", $filterParams);
	}
  //Asociar todos los parametros a un sql
	function bindAllValues($statement, $params)
  {
		foreach($params as $param => $value)
    {
				$statement->bindValue(':'.$param, $value);
		}
		return $statement;
   }
 ?>

Finalmente, este es el archivo que implementa el servicio RESTful

<?php
include "config.php";
include "utils.php";
$dbConn =  connect($db);
/*
  listar todos los posts o solo uno
 */
if ($_SERVER['REQUEST_METHOD'] == 'GET')
{
    if (isset($_GET['id']))
    {
      //Mostrar un post
      $sql = $dbConn->prepare("SELECT * FROM posts where id=:id");
      $sql->bindValue(':id', $_GET['id']);
      $sql->execute();
      header("HTTP/1.1 200 OK");
      echo json_encode(  $sql->fetch(PDO::FETCH_ASSOC)  );
      exit();
	  }
    else {
      //Mostrar lista de post
      $sql = $dbConn->prepare("SELECT * FROM posts");
      $sql->execute();
      $sql->setFetchMode(PDO::FETCH_ASSOC);
      header("HTTP/1.1 200 OK");
      echo json_encode( $sql->fetchAll()  );
      exit();
	}
}
// Crear un nuevo post
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $input = $_POST;
    $sql = "INSERT INTO posts
          (title, status, content, user_id)
          VALUES
          (:title, :status, :content, :user_id)";
    $statement = $dbConn->prepare($sql);
    bindAllValues($statement, $input);
    $statement->execute();
    $postId = $dbConn->lastInsertId();
    if($postId)
    {
      $input['id'] = $postId;
      header("HTTP/1.1 200 OK");
      echo json_encode($input);
      exit();
	 }
}
//Borrar
if ($_SERVER['REQUEST_METHOD'] == 'DELETE')
{
	$id = $_GET['id'];
  $statement = $dbConn->prepare("DELETE FROM posts where id=:id");
  $statement->bindValue(':id', $id);
  $statement->execute();
	header("HTTP/1.1 200 OK");
	exit();
}
//Actualizar
if ($_SERVER['REQUEST_METHOD'] == 'PUT')
{
    $input = $_GET;
    $postId = $input['id'];
    $fields = getParams($input);
    $sql = "
          UPDATE posts
          SET $fields
          WHERE id='$postId'
           ";
    $statement = $dbConn->prepare($sql);
    bindAllValues($statement, $input);
    $statement->execute();
    header("HTTP/1.1 200 OK");
    exit();
}
//En caso de que ninguna de las opciones anteriores se haya ejecutado
header("HTTP/1.1 400 Bad Request");
?>

Ahora voy a explicar un poco el último archivo, como ya sabes en RESTful la acción a ejecutar depende mucho del método HTTP que utilizas, entonces utilizo la variable $_SERVER['REQUEST_METHOD'], para determinar si se está haciendo una petición GET, POST, DELETE o PUT.

Con la sentencia header("HTTP/1.1 200 OK"), puedo enviar códigos de respuesta, para informar si el servicio se ejecutó con éxito o con algún error.

Con la sentencia json_encode de php, se transforma la salida de echo en un formato JSON, lo cual es necesario en los servicios RESTful.

Como probar el servicio RESTful

Los servicios RESTful no se pueden probar en un navegador, porque no hay forma de enviar peticiones PUT o DELETE, entonces podemos usar un programa especial como postman.

Nota: Si has disfrutado este u otro de mis artículos sobre RESTful, seguramente vas a disfrutar mi libro sobre RESTful disponible en amazon.com y también en amazon.es a un precio increíble y lleno de muchos temas.

Mejoras a este programa.

Escribí este código para mostrarte como implementar un web service RESTFul usando PHP, y para mantener el código sencillo omití algunas validaciones que no debería de faltar en un ambiente de producción, por ejemplo:

Cuando realizas el update, no deberías de permitir actualizar todos los campos, por ejemplo, campos de fecha de creación, usuario que modifica, etc.

En caso de que se solicite un post por ID y el ID no exista debería de retornar un código 404 Not found. Lo mismo aplica para editar o eliminar.

También hace falta una forma de autenticarse antes de permitir acceso a los métodos de eliminar, actualizar o insertar información.

Deja una respuesta

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

22 Comments

    1. Avatar de lcruz

      Hola, aquí hay un artículo sobre como probar métodos put, post, delete, etc., ahí explico todo paso a paso, si tienes alguna duda, me puedes dejar otro comentario

  1. Avatar de Victor hugo
    Victor hugosays:

    Hola, actualmente estoy haciendo una aplicacion en ios y necesito consumir servicios, en este caso y para mayor facilidad quisiera crear mis servicios con php porque conozco algo del lenguaje.
    Mi pregunta es, donde subo la base de datos y los archivos php para poder consumirlos desde mi app ?
    Quizá mi pregunta sea un poco o muy tonta pero la verdad es que en el tema de los servicios estoy totalmente perdido pero el tutorial esta buenísimo.
    Gracias

    1. Avatar de lcruz

      Hola, los archivos de php y la base de datos, la tendrias que subir en un servidor web. No si tienes presupuesto para pagarlo, en mi caso yo uso uno y pago 5.00 $USD al mes, podrías conseguir uno mas barato, pero lo más importante es la estabilidad del servidor, que este siempre disponible. Luego para consumir el servicio, eso ya depende del lenguaje de programacion que decidas usar. Has escuchado de las aplicaciones hibridas?, como las que se hacen con ionic, asi puedes hacer tu aplicacion y funciona en android y ios.

  2. Avatar de Gonzalo

    Buenas, muchas gracias por el tutorial, lo tengo funcionando.

    Sin embargo tengo un problema, en mi tabla de la base de datos tengo algunas campos de tipo text y medium text, cuando el contenido de estos campos supera unos 10/15 caracteres todo deja de funcionar. Al hacer un GET se recibe la respuesta correcta (200) pero deja de mandar el contenido de la tabla en JSON, no se recibe nada.

    1. Avatar de Dax

      EL error es en la definicion de los campos en la base de datos, porque solo admite 11 caracteres tienes que modificar los atributos de la base de datos y ponerle 20 por ejemplo

  3. Avatar de Abraham

    Hola que tal, hice el ejemplo y me funciona correctamente en local pero al subirlo a mi sitio web y tratar de probarlo con postman simplemente no devuelve nada, intente el get y no regresa nada la pagina de postman que se encuentra abajo esta en blanco, estuve leyendo y al parecer tengo que activar algo de httacces esto es cierto?, o cual seria mi error, gracias uso xpress hosting

  4. Avatar de Abraham

    Lo he subido a mi sitio web que esta en xpress hosting, lo he conectado a la bd de phpMyAdmin que me brinda el servidor y aun me lanza un error el cual es SQLSTATE[HY000] [2002] Connection refused, alguien podría ayudarme por favor, y gracias.

    1. Avatar de lcruz

      Quizá puedas compartir como haces la conexión (QUITANDO EL VERDADERO PASSWORD Y USUARIO!!!!!). Lo que se me ocurre es que en la ip o nombre del servidor debes poner 127.0.0.1 si pones la ip publica o el dominio quizá la rechaza por seguridad

  5. Avatar de Mr.Soap

    Hola buenas tardes.
    Soy un programador junior haciendo su primer web service y para poder usar imagenes de un servidor en su web, pero al convertirse en json y buscar la url de la imagen me muestra un error. espero su ayuda

  6. Avatar de jose

    Hola ,el baner publicitario inferior modifica constantemente la disposicion del contenido haciendo muy incomoda la lectura del post.Es una lastima,pues el contenido es muy interesante,pero la experiencia de usuario es nefasta.

    1. Avatar de lcruz

      Gracias por tu comentario, cuando probe el anuncio el año pasado no era así, supongo que la empresa que administra los anuncios hizo un cambio, les voy a escribir para ver si lo pueden arreglar, y si no se puede arreglarlo lo voy a quitar o cambiar de empresa.

      Me importa la experiencia de usuario, por eso pago por un servidor que es más caro que un hosting compartido y otros servicios, y los anuncios son la forma de pagar por esos costos, lo siento. Y de nuevo gracias por reportar el problema.

    1. Avatar de lcruz

      Hola, si tienes razon, pero este es un ejemplo, cuando publicas un servicio lo proteges con un usuario y clave o con un apikey para que solo tengan acceso las personas que tu autorizas.

  7. Avatar de Celes

    Estoy haciendo DEW y nos han pedido esto en una práctica. Tu tutorial me ha venido genial. Muchas gracias.
    Saludos.

  8. Avatar de Yair Adrian Becerril Miramar
    Yair Adrian Becerril Miramarsays:

    ¿Nos podrías compartir la configuración de PHP?

    Me da un error 500 y es posiblemente por que alguna configuración de PHP falta.