How to Write a REST API in PHP in 30 Minutes
Creating your own REST API is one of the key skills of a modern backend developer. Many beginners think that heavy frameworks like Laravel or Symfony are required for this. In reality, a basic REST API in pure PHP can be written in literally half an hour. In this article, we will break down the step-by-step process of creating a RESTful service that can be immediately used in real projects — from mobile applications to single-page websites.
We will not use third-party libraries. All the code will be written in vanilla PHP. You will learn how to handle HTTP requests, work with JSON, organize routing, and return correct HTTP statuses. Let's go!
1. Project Structure and Preparation
Before writing code, let's create a simple file structure. For our API, we will only need a few files:
index.php— the entry point that will handle all requests;.htaccess— for redirecting all requests to index.php (if you are using Apache);config.php— a file with database connection settings (optional).
Create a project folder, for example, my-rest-api, and place these files there.
Setting up .htaccess
To ensure all requests reach our main script, create a .htaccess file in the project root:
RewriteEngine OnRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php [QSA,L]This code redirects all requests that do not point to real files or folders to index.php. The QSA parameter preserves the query string.
2. Routing and Request Handling
Now let's write the main file — index.php. It will accept the request, determine the HTTP method (GET, POST, PUT, DELETE) and the path, and then call the appropriate handler.
Basic Routing
Let's start with a simple example. We'll create an array of routes and a function to handle them:
<?phpheader('Content-Type: application/json');header('Access-Control-Allow-Origin: *');header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');header('Access-Control-Allow-Headers: Content-Type');
$method = $_SERVER['REQUEST_METHOD'];$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// Remove trailing slash$path = rtrim($path, '/');
// Simple routingswitch (true) { case $path === '/api/users' && $method === 'GET': getUsers(); break; case $path === '/api/users' && $method === 'POST': createUser(); break; case preg_match('/^\\/api\\/users\\/(\\d+)$/', $path, $matches) && $method === 'GET': getUser($matches[1]); break; default: http_response_code(404); echo json_encode(['error' => 'Route not found']); break;}
function getUsers() { // Stub echo json_encode(['users' => ['Alice', 'Bob', 'Charlie']]);}
function getUser($id) { echo json_encode(['user' => ['id' => $id, 'name' => 'User ' . $id]]);}
function createUser() { $input = json_decode(file_get_contents('php://input'), true); echo json_encode(['message' => 'User created', 'data' => $input]);}?>Pay attention to a few important points:
- We set the
Content-Type: application/jsonheader — all responses will be in JSON. - CORS headers allow requests from any domain (for development).
- The body of a POST/PUT request is read via
php://input.
3. Working with a Database
A real API rarely works with stubs. Let's add a MySQL connection using PDO. Create a config.php file:
<?phpdefine('DB_HOST', 'localhost');define(