Skip to main content
RESTful Principles
CHAPTER 20 Beginner

Building REST APIs with PHP

Updated: May 13, 2026
5 min read

# CHAPTER 20

Building REST APIs with PHP

1. Introduction

We have spent 19 chapters discussing theory, architecture, and concepts. It is time to roll up our sleeves and write code. In Chapter 20, we will build a functional REST API foundation using pure Core PHP (without heavy frameworks like Laravel or Symfony). We will learn how to set up an index.php router, structure our files, read incoming JSON, and format outgoing JSON responses properly.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Structure a basic PHP directory for an API project.
  • Implement a front-controller routing system using index.php.
  • Parse URL paths and HTTP methods dynamically.
  • Read JSON payloads from php://input.
  • Create a helper function to output standardized JSON responses.

3. Beginner-Friendly Explanation

When building an API in PHP, you don't create a separate file for every single endpoint (e.g., getusers.php, deleteuser.php). That gets messy fast. Instead, we use a Front Controller pattern. All traffic (no matter the URL) is forced to go to one single file: index.php. Think of index.php as the receptionist at an office building. You tell the receptionist where you want to go (/users, POST), and the receptionist looks at their map (the Router) and sends you to the correct office (the Controller).

4. Real-World Examples

  • Frameworks: This exact routing pattern is what powers massive frameworks like Laravel, CodeIgniter, and Express.js. All requests funnel through one entry point to ensure security, validation, and database connections are initialized once.

5. Detailed Code Examples

Let's build the core engine of our API.

1. .htaccess (Apache configuration to force all traffic to index.php):

apache
1234
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?request=$1 [QSA,NC,L]

2. index.php (The Router / Front Controller):

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

// Helper function to send JSON responses
function sendResponse($status, $data) {
    http_response_code($status);
    echo json_encode($data);
    exit;
}

// Get the requested URL path
$uri = parse_url($_SERVER[&#039;REQUEST_URI'], PHP_URL_PATH);
$uri = explode(&#039;/', $uri);
$method = $_SERVER["REQUEST_METHOD"];

// Handle CORS Preflight
if ($method == "OPTIONS") {
    sendResponse(200, ["message" => "OK"]);
}

// Basic Routing Logic
if (isset($uri[2]) && $uri[2] == &#039;users') {
    $userId = $uri[3] ?? null;

    if ($method == &#039;GET') {
        if ($userId) {
            sendResponse(200, ["message" => "Get user $userId"]);
        } else {
            sendResponse(200, ["message" => "Get all users"]);
        }
    } 
    
    elseif ($method == &#039;POST') {
        // Reading incoming JSON payload
        $input = json_decode(file_get_contents(&#039;php://input'), true);
        sendResponse(201, ["message" => "User created", "data" => $input]);
    }
    
    else {
        sendResponse(405, ["error" => "Method not allowed"]);
    }
} else {
    sendResponse(404, ["error" => "Endpoint not found"]);
}
?>

6. Request/Response Examples

Using the engine we just built above:

Request:

http
1234567
POST /api/users HTTP/1.1
Host: localhost
Content-Type: application/json

{
  "name": "Alice"
}

Response:

json
123456
{
  "message": "User created",
  "data": {
    "name": "Alice"
  }
}

7. HTTP Examples

The headers added at the top of index.php are critical for modern APIs:
  • Access-Control-Allow-Origin: * allows frontend apps (like React running on a different port) to access the API without CORS blocking.
  • Content-Type: application/json ensures the browser interprets the output as JSON data, not HTML text.

8. JSON Examples

Our sendResponse() helper function ensures our API never accidentally outputs raw text. Even if we send a string, it gets wrapped in a JSON object.
php
12345
// Calling this:
sendResponse(404, ["error" => "File not found"]);

// Will always output valid JSON:
// {"error": "File not found"}

9. Best Practices

  • Separate Logic from Routing: In the example above, we put the logic directly inside index.php. For a real app, index.php should merely *call* a separate class (like UserController.php) to keep files clean.
  • Always handle OPTIONS: Browsers send OPTIONS preflight requests before making POST/PUT requests from a frontend app. If your PHP script doesn't handle OPTIONS and return a 200 OK, the browser will block the real request.
  • Centralize Output: Never echo or printr randomly in your code. Always use a centralized function like sendResponse() so you have one place to format your JSON structure.

10. Common Mistakes

  • Forgetting the .htaccess file: If you don't configure Apache/Nginx to route requests to index.php, requesting /users will just result in a 404 Apache error because the actual folder /users doesn't exist on the server.
  • Accidental Whitespace: If you have a blank line before the <?php tag, PHP will output a blank space before the JSON. This makes the JSON invalid and will crash your frontend app when it tries to parse it.

11. Mini Exercises

  1. 1. Look at the parseurl logic. If a client requests http://localhost/api/users/5, what value will be stored in $uri[2] and $uri[3]?
*(Answer: $uri[2] is 'users', $uri[3] is '5')*

12. Coding Challenges

Challenge 1: Add a new routing block to the index.php example to handle a /products endpoint. Make it respond to GET requests with {"message": "List of products"}.

13. MCQs with Answers

Question 1

What is the purpose of the .htaccess file in a PHP API?

Question 2

Why is the OPTIONS method specifically handled at the top of the script?

Question 3

How do you ensure your PHP API always returns data as JSON instead of HTML?

14. Interview Questions

  • Q: Explain the "Front Controller" design pattern and why it is superior to creating separate PHP files for every endpoint.
  • Q: How do you handle CORS (Cross-Origin Resource Sharing) in a raw PHP API?
  • Q: Walk me through how you extract the resource name and ID from a URL string in PHP without using a framework.

15. FAQs

Q: This seems like a lot of work. Shouldn't I just use Laravel? A: Frameworks like Laravel are excellent and are the industry standard for large apps. However, building an API in raw PHP is a crucial learning step. It teaches you *how* HTTP and routing actually work under the hood, making you a much better developer when you eventually switch to a framework.

16. Summary

In Chapter 20, we moved from theory to practical PHP implementation. We built a robust API foundation using the Front Controller pattern, utilizing .htaccess to route all traffic to index.php. We set up CORS headers, dynamically parsed the requested URL and HTTP method, read incoming JSON payloads, and created a helper function to guarantee perfectly formatted JSON responses.

17. Next Chapter Recommendation

Our API can route traffic and return JSON, but it currently has no memory. Proceed to Chapter 21: Connecting REST APIs with MySQL to hook our routing engine up to a real database using PDO.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·