Cómo Implementar una API RESTful con CRUD Usando PHP y MySQL

06/08/2024 | Apache, MySQL, PHP | 0 comentarios

Implementa una API RESTful con CRUD en PHP y MySQL usando PDO con este práctico tutorial paso a paso.

Descargar archivos


En este artículo, explicaremos cómo implementar una API Restful con operaciones CRUD (Crear, Leer, Actualizar y Eliminar) utilizando PHP con PDO (PHP Data Objects) y MySQL. Esta guía te llevará paso a paso a través del proceso de configuración y desarrollo de tu API.

Requisitos Previos

  • Un servidor web con PHP instalado (como Apache o Nginx).
  • Un servidor de base de datos MySQL.
  • Conocimientos básicos de PHP y SQL.

CRUD

CRUD es un acrónimo que se refiere a las cuatro operaciones básicas que se pueden realizar en una base de datos:

OperaciónSQLMétodo HTTP
Create: Agregar nuevos registros a la base de datos.INSERTPOST
Read: Leer registros de la base de datos.SELECTGET
Update: Modificar registros existentes en la base de datosUPDATEPUT
Delete: Borrar registros de la base de datos.DELETEDELETE

Base de datos

Para empezar se necesita una tabla donde guardaremos los datos, creamos la tabla users con cinco campos para los datos de nuestros usuarios:


CREATE TABLE users
(
    id         INT AUTO_INCREMENT PRIMARY KEY,
    name       VARCHAR(100) NOT NULL,
    email      VARCHAR(100) NOT NULL,
    phone      INT          NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Conexión a Base de Datos

Para empezar creamos el archivo config.php, donde colocaremos los datos de conexión a nuestra base de datos.


<?php
// file: config.php
define('DB_HOST',     'localhost');   // database server
define('DB_DATABASE', 'apidb');       // database name
define('DB_USERNAME', 'user');        // database user
define('DB_PASSWORD', 'pass');        // database password

Creamos el archivo libray/database.php con una clase PHP responsable de hacer la conexión con la base de datos. En la clase usamos el patrón de diseño Singleton para devolver una instancia de la conexión y evitar que se generen múltiples conexiones


<?php
// file: library/Database.php
include_once '../config.php';

class Database
{
    private static $instance = null;
    private $pdo;

    public function __construct()
    {
        $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
        $options = array(
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4'",
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        try {
            $this->pdo = new PDO($dsn, DB_USERNAME, DB_PASSWORD, $options);
        } catch (PDOException $exception) {
            throw new Exception($exception->getMessage());
        }
    }

    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new Database();
        }
        return self::$instance->pdo;
    }
}

Modelo

Para el manejo de los datos, vamos a usar un modelo llamado User que se ubicará en el archivo models/User.php. En esta clase primero creamos una instancia de la conexión en la propiedad $this->pdo, luego de ello creamos cuatro métodos para el manejo de los datos:

  • read(): Devuelve el listado de usuarios.
  • create(): Crea un nuevo usuario en la tabla.
  • update(): Modifica los datos de un usuario.
  • delete(): Elimina los datos de un usuario seleccionado.

<?php
// file: models/User.php
include_once '../library/Database.php';

class User
{
    private $pdo;

    public $id;
    public $name;
    public $email;
    public $phone;

    public function __construct()
    {
        $this->pdo = Database::getInstance();
    }

    public function read()
    {
        $query = "SELECT * FROM users";
        $stmt = $this->pdo->prepare($query);
        $stmt->execute();
        return $stmt;
    }

    public function create()
    {
        $this->name = filter_var($this->name, FILTER_SANITIZE_STRING);
        $this->email = filter_var($this->email, FILTER_SANITIZE_EMAIL);
        $this->phone = filter_var($this->phone, FILTER_SANITIZE_NUMBER_INT);

        $query = "INSERT INTO users SET name=:name, email=:email, phone=:phone";
        $stmt = $this->pdo->prepare($query);
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":email", $this->email);
        $stmt->bindParam(":phone", $this->phone);
        if ($stmt->execute()) {
            return true;
        }
        return false;
    }

    public function update()
    {
        $this->id = filter_var($this->id, FILTER_SANITIZE_NUMBER_INT);
        $this->name = filter_var($this->name, FILTER_SANITIZE_STRING);
        $this->email = filter_var($this->email, FILTER_SANITIZE_EMAIL);
        $this->phone = filter_var($this->phone, FILTER_SANITIZE_NUMBER_INT);

        if ($this->id > 0) {
            $query = "UPDATE users SET name=:name, email=:email, phone=:phone WHERE id=:id";
            $stmt = $this->pdo->prepare($query);
            $stmt->bindParam(':name', $this->name);
            $stmt->bindParam(':email', $this->email);
            $stmt->bindParam(':phone', $this->phone);
            $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
            if ($stmt->execute()) {
                return true;
            }
        }
        return false;
    }

    public function delete()
    {
        $this->id = filter_var($this->id, FILTER_SANITIZE_NUMBER_INT);

        if ($this->id > 0) {
            $query = "DELETE FROM users WHERE id=:id";
            $stmt = $this->pdo->prepare($query);
            $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
            if ($stmt->execute()) {
                return true;
            }
        }
        return false;
    }
}

Controlador

Lo siguiente es crear el archivo controllers/UserController.php con la clase que controle los métodos HTTP solicitados. Notar que la solicitud y respuesta están en formato JSON por lo que usamos usamos json_decode y json_encode, además se usa http_response_code para devolver status HTTP correcto.


<?php
// file: controllers/UserController.php
include_once '../models/User.php';

$user = new User();
$request = $_SERVER["REQUEST_METHOD"];

switch ($request) {
    case 'GET':
        $stmt = $user->read();
        $num = $stmt->rowCount();

        if ($num > 0) {
            $response = array("message" => "ok", "data" => array());
            while ($result = $stmt->fetch()) {
                $response["data"][] = array(
                    "id" => $result->id,
                    "name" => $result->name,
                    "email" => $result->email,
                    "phone" => $result->phone,
                    "created_at" => $result->created_at
                );
            }

            http_response_code(200);
            echo json_encode($response);
        } else {
            http_response_code(404);
            echo json_encode(array("message" => "No users found."));
        }
        break;

    case 'POST':
        $data = json_decode(file_get_contents("php://input"));

        if (!empty($data->name) && !empty($data->email)) {
            $user->name = $data->name;
            $user->email = $data->email;
            $user->phone = $data->phone;

            if ($user->create()) {
                http_response_code(201);
                echo json_encode(array("message" => "User was created."));
            } else {
                http_response_code(503);
                echo json_encode(array("message" => "Unable to create user."));
            }
        } else {
            http_response_code(400);
            echo json_encode(array("message" => "Unable to create user. Data incomplete."));
        }
        break;

    case 'PUT':
        $data = json_decode(file_get_contents("php://input"));

        if (!empty($data->id) && !empty($data->name) && !empty($data->email)) {
            $user->id = $data->id;
            $user->name = $data->name;
            $user->email = $data->email;
            $user->phone = $data->phone;

            if($user->update()) {
                http_response_code(200);
                echo json_encode(array("message" => "User was updated."));
            } else {
                http_response_code(503);
                echo json_encode(array("message" => "Unable to update user."));
            }
        } else {
            http_response_code(400);
            echo json_encode(array("message" => "Unable to update user. Data is incomplete."));
        }
        break;

    case 'DELETE':
        $data = json_decode(file_get_contents("php://input"));
        $user->id = $data->id;

        if ($user->delete()) {
            http_response_code(200);
            echo json_encode(array("message" => "User was deleted."));
        } else {
            http_response_code(503);
            echo json_encode(array("message" => "Unable to delete user."));
        }
        break;

    default:
        http_response_code(405);
        echo json_encode(array("message" => "Method not allowed."));
        break;
}

Enrutamiento

Creamos el archivo routes/user.php donde agregamos los headers necesarios para recibir y responder datos en formato JSON y los métodos HTTP aceptados, finalmente incluimos el controlador que va a procesar las solicitudes:


<?php
// file: routes/user.php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Max-Age: 3600");

include_once '../controllers/UserController.php';

Ruta amigable

En el archivo .htaccess, configuramos las reglas de reescritura para las URLs amigables.


RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(user/)$ routes/user.php?/$1 [L]

Pruebas

Puedes probar tu API usando herramientas como Postman o cURL. Por ejemplo para obtener la lista de usuarios con cURL debes ejecutar lo siguiente en tu línea de comandos:

curl --location 'http://localhost/user/'

Para crear un nuevo usuario usando cURL, se hace con el siguiente comando:


curl --location 'http://localhost/user/' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "John Doe 666",
    "email": "john@example.com",
    "phone": "999399449"
}'

También puede usar Postman que ofrece una interfaz intuitiva y sencilla de utilizar.

Conclusión

Hemos creado una API Restful con operaciones CRUD utilizando PHP y PDO para interactuar con una base de datos MySQL. Esta configuración puede ser ampliada y personalizada según tus necesidades, incluyendo autenticación, validación de datos y manejo de errores mejorado.

Referencias

Envíar Comentario

En este sitio los comentarios se publican previa aprobación del equipo de Kodetop. Evita los comentarios ofensivos, obscenos o publicitarios. Si deseas publicar código fuente puedes hacerlo entre las etiquedas <pre></pre>