Building a Simple REST API in Native PHP

 


Creating a REST API in PHP is straightforward, even without frameworks like Laravel or Symfony. In this tutorial, we’ll go over the basics of setting up a simple REST API using only native PHP. This is perfect for beginners and small projects that don’t require a complex framework.

What is a REST API?

REST (Representational State Transfer) APIs allow applications to communicate over HTTP by sending requests to access or manipulate data. A RESTful API typically includes HTTP methods like GET, POST, PUT, and DELETE, which correspond to CRUD (Create, Read, Update, Delete) operations.

Prerequisites

  • PHP installed on your system.
  • A basic understanding of PHP and HTTP methods.
  • A simple database (we’ll use MySQL in this example).

Project Structure

For this example, our project will have the following structure:

project-folder/
├── api/
   ├── config.php
   ├── database.php
   ├── categories.php
   └── products.php
├── products/
   └── index.php
├── categories/
   └── index.php
└── index.php

Note

For simplicity, this tutorial focuses on a single entity, products. However, you can apply similar logic to create additional APIs for other entities, such as categories, orders, or customers. Once you're comfortable with these basic steps, try expanding this API by adding endpoints for related data or new functionality.

Step 1: Setting Up the Database

Create a MySQL database and a table for the example. This example uses a products table with some sample fields.

SQL to create the products table:

CREATE DATABASE test_api;

USE test_api;

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL
);

Step 2: Database Configuration (config.php)

In the api folder, create a config.php file to store the database connection details.

<?php
// api/config.php

define('DB_HOST', 'localhost');
define('DB_NAME', 'test_api');
define('DB_USER', 'root');
define('DB_PASS', '');
?>

Step 3: Database Connection Class (database.php)

Create a database.php file in the api folder to handle the database connection.

<?php
// api/database.php

class Database {
    private $host = DB_HOST;
    private $db_name = DB_NAME;
    private $username = DB_USER;
    private $password = DB_PASS;
    public $conn;

    public function getConnection() {
        $this->conn = null;
        try {
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $exception) {
            echo "Connection error: " . $exception->getMessage();
        }
        return $this->conn;
    }
}
?>

Step 4: Creating the API Endpoints (products.php)

This file will handle the main API logic. It will listen for different HTTP methods and respond accordingly.

<?php
// api/products.php
include_once 'config.php';
include_once 'database.php';

header("Content-Type: application/json; charset=UTF-8");

$database = new Database();
$db = $database->getConnection();

$requestMethod = $_SERVER["REQUEST_METHOD"];
$request = explode("/", trim($_SERVER["REQUEST_URI"], "/"));

$resource = $request[1] ?? null;

if ($resource !== 'products') {
    echo json_encode(["message" => "Resource not found."]);
    exit();
}

switch ($requestMethod) {
    case 'GET':
        if (isset($_GET['id']) && is_numeric($_GET['id'])) {
            getProduct($_GET['id']);
        } else {
            getProducts();
        }
        break;
    case 'POST':
        createProduct();
        break;
    case 'PUT':
        if (isset($_GET['id']) && is_numeric($_GET['id'])) {
            updateProduct($_GET['id']);
        } else {
            echo json_encode(["message" => "Provide id to updates"]);
        }
        break;
    case 'DELETE':
        if (isset($_GET['id']) && is_numeric($_GET['id'])) {
            deleteProduct($_GET['id']);
        } else {
            echo json_encode(["message" => "Provide id to updates"]);
        }
        break;
    default:
        echo json_encode(["message" => "Method not allowed"]);
        break;
}

function getProducts() {
    global $db;
    $query = "SELECT * FROM products";
    $stmt = $db->prepare($query);
    $stmt->execute();

    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
    echo json_encode($products);
}

function getProduct($id) {
    global $db;
    $query = "SELECT * FROM products WHERE id = ?";
    $stmt = $db->prepare($query);
    $stmt->execute([$id]);

    $product = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($product) {
        echo json_encode($product);
    } else {
        echo json_encode(["message" => "Product not found"]);
    }
}

function createProduct() {
    global $db;
    $data = json_decode(file_get_contents("php://input"), true);
    $query = "INSERT INTO products (name, description, price) VALUES (?, ?, ?)";
    $stmt = $db->prepare($query);

    if ($stmt->execute([$data['name'], $data['description'], $data['price']])) {
        echo json_encode(["message" => "Product created"]);
    } else {
        echo json_encode(["message" => "Failed to create product"]);
    }
}

function updateProduct($id) {
    global $db;
    $data = json_decode(file_get_contents("php://input"), true);
    $query = "UPDATE products SET name = ?, description = ?, price = ? WHERE id = ?";
    $stmt = $db->prepare($query);

    if ($stmt->execute([$data['name'], $data['description'], $data['price'], $id])) {
        echo json_encode(["message" => "Product updated"]);
    } else {
        echo json_encode(["message" => "Failed to update product"]);
    }
}

function deleteProduct($id) {
    global $db;
    $query = "DELETE FROM products WHERE id = ?";
    $stmt = $db->prepare($query);

    if ($stmt->execute([$id])) {
        echo json_encode(["message" => "Product deleted"]);
    } else {
        echo json_encode(["message" => "Failed to delete product"]);
    }
}
?>

Step 5: Routing Requests to products.php

In the products folder, create an index.php file to handle incoming requests and redirect them to products.php inside api folder.

<?php
// index.php

require '../api/products.php';

Step 6: Testing the API

With the API set up, you can test it using a tool like Postman or cURL.

Example Requests

  • GET All Products: GET https://domain-name.com/project-folder/products/
  • GET Product by ID: GET https://domain-name.com/project-folder/products?id=1
  • POST Create Product: POST https://domain-name.com/project-folder/products/ with JSON body:
{
  "name": "New Product",
  "description": "This is a test product",
  "price": 9.99
}

  • PUT Update Product: PUT https://domain-name.com/project-folder/products?id=1 with JSON body
{
  "name": "Updated Product",
  "description": "This is an updated description",
  "price": 19.99
}

  • DELETE Product: DELETE https://domain-name.com/project-folder/products?id=1

Download the Postman Collection

To make testing even easier, you can download a Postman collection pre-configured with all the API endpoints used in this tutorial. Simply import the collection into Postman and start sending requests.

Postman Logo Download Postman Collection for Products API

To import the collection you can check this link on How to Import data into Postman.

Conclusion

In this article, we built a simple REST API using native PHP, which handles CRUD operations for a products table in MySQL. This approach is ideal for small applications or for developers who want to learn the fundamentals of REST APIs in PHP. With this setup, you can expand the API by adding authentication, validation, and additional resources.

Creating a REST API using native PHP is a great way to understand the basics of web development and data handling. Once you have mastered this, you can enhance your API with other features, such as:

  • Authentication and Authorization
  • Error Handling and Validation
  • Pagination and Sorting

Experiment with different objects to build a full-fledged backend API for a web or mobile application.

Previous Post Next Post

نموذج الاتصال