Thursday, May 22, 2025

How to Build REST APIs in PHP and Laravel: A Step-by-Step Guide

 

Prerequisites

Before diving into development, ensure you have the following:

- A working installation of PHP (7.4 or higher recommended)
- Composer (Dependency manager for PHP)
- MySQL or any other database server
- A code editor like VS Code or PHPStorm
- Basic knowledge of PHP and HTTP methods (GET, POST, PUT, DELETE)

Optional but helpful:
- Postman or cURL for API testing

Step 1: Project Structure

Start by organizing your project files. A clean structure helps in scaling and maintaining the codebase.

rest-api-php/

├── .htaccess
├── config/
   └── database.php
├── public/
   └── index.php
├── src/
   ├── controllers/
   ├── models/
   └── routes/
├── vendor/
├── composer.json


Step 2: Initialize the Project with Composer

Create a new directory and initialize a Composer project:


mkdir rest-api-php && cd rest-api-php
composer init

Then, add a simple router like Bramus Router:


composer require bramus/router

Step 3: Set Up Routing

In `public/index.php`, set up the entry point of the application.


<?php
require_once '../vendor/autoload.php';

use Bramus\Router\Router;

$router = new Router();

// Include your route definitions
require_once '../src/routes/api.php';

$router->run();

Now, create your `src/routes/api.php` file to define API routes:


<?php
$router->get('/users', 'UserController@getAll');
$router->post('/users', 'UserController@create');
$router->get('/users/(\d+)', 'UserController@getOne');
$router->put('/users/(\d+)', 'UserController@update');
$router->delete('/users/(\d+)', 'UserController@delete');

Step 4: Database Connection

Create a file `config/database.php` for handling DB connections.


<?php
class Database {
    private $host = "localhost";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "";
    public $conn;

public function connect() {
        $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 $e) {
            echo "Connection error: " . $e->getMessage();
        }

return $this->conn;
    }
}

Step 5: Building the Controller

Create a `UserController` inside `src/controllers/UserController.php`.


<?php
require_once __DIR__ . '/../models/User.php';

class UserController {
    public function getAll() {
        $user = new User();
        echo json_encode($user->findAll());
    }

public function getOne($id) {
        $user = new User();
        echo json_encode($user->findById($id));
    }

public function create() {
        $data = json_decode(file_get_contents("php://input"), true);
        $user = new User();
        echo json_encode($user->create($data));
    }

public function update($id) {
        $data = json_decode(file_get_contents("php://input"), true);
        $user = new User();
        echo json_encode($user->update($id, $data));
    }

public function delete($id) {
        $user = new User();
        echo json_encode($user->delete($id));
    }
}

Step 6: Creating the Model

Define your data logic inside `src/models/User.php`.

<?php
require_once __DIR__ . '/../../config/database.php';

class User {
    private $conn;

public function __construct() {
        $db = new Database();
        $this->conn = $db->connect();
    }

public function findAll() {
        $stmt = $this->conn->prepare("SELECT * FROM users");
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

public function findById($id) {
        $stmt = $this->conn->prepare("SELECT * FROM users WHERE id = ?");
        $stmt->execute([$id]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

public function create($data) {
        $stmt = $this->conn->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
        $stmt->execute([$data['name'], $data['email']]);
        return ['id' => $this->conn->lastInsertId()];
    }

public function update($id, $data) {
        $stmt = $this->conn->prepare("UPDATE users SET name = ?, email = ? WHERE id = ?");
        $stmt->execute([$data['name'], $data['email'], $id]);
        return ['status' => 'updated'];
    }

public function delete($id) {
        $stmt = $this->conn->prepare("DELETE FROM users WHERE id = ?");
        $stmt->execute([$id]);
        return ['status' => 'deleted'];
    }
}

Step 7: Securing the API

To avoid unauthorized access:

- Use API tokens or JWT for authentication.
- Sanitize and validate all inputs.
- Set up CORS headers.

Example for CORS headers in `index.php`:


header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");

Step 8: Testing the API

Use Postman or cURL to test your endpoints:

# GET all users
curl http://localhost:8000/users

# POST create user
curl -X POST http://localhost:8000/users      -H "Content-Type: application/json"      -d '{"name": "John", "email": "john@example.com"}'

Final Tips

- Avoid returning raw SQL errors in responses.
- Use HTTP status codes appropriately.
- Consider using a micro-framework like Lumen or Slim for more advanced API handling.

Conclusion

Building REST APIs in PHP doesn’t have to be a daunting task. With a clear structure and tools like Bramus Router and PDO, you can get a lightweight API up and running quickly. Whether you're building a small internal API or powering a large application, these foundational steps will serve you well.