Skip to main content
RESTful Principles
CHAPTER 29 Beginner

Building a Complete RESTful Project API

Updated: May 13, 2026
5 min read

# CHAPTER 29

Building a Complete RESTful Project API

1. Introduction

Welcome to the Capstone Project. You have spent the last 28 chapters learning the concepts, architecture, security, and performance of REST APIs. In Chapter 29, we will synthesize all of this knowledge into a single, cohesive project. We will architect and outline a complete, production-ready REST API for a Task Management System (like Trello or Asana).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Architect the database schema for a multi-resource API.
  • Design clean, RESTful URL endpoints for complex relationships.
  • Implement token-based authentication and route protection.
  • Structure a modular PHP codebase (Router, Controllers, Models).
  • Apply validation, error handling, and status codes in a unified system.

3. Project Overview

The App: "TaskMaster API" Features:
  • Users can register and log in to receive a JWT or Bearer Token.
  • Users can create, read, update, and delete "Projects".
  • Users can create, read, update, and delete "Tasks" within a Project.
  • Users can ONLY access their own Projects and Tasks (Authorization).

4. Database Architecture

A solid API starts with a solid relational database.
sql
1234567891011121314151617181920212223
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100) UNIQUE,
    password_hash VARCHAR(255),
    api_token VARCHAR(100) UNIQUE
);

CREATE TABLE projects (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT, -- Foreign Key
    title VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    project_id INT, -- Foreign Key
    title VARCHAR(255),
    status ENUM('pending', 'in_progress', 'completed') DEFAULT 'pending',
    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);

5. API Endpoint Design (The Contract)

Before writing PHP, we define our endpoints perfectly.

Authentication:

  • POST /api/v1/register (Creates user)
  • POST /api/v1/login (Returns API Token)

Projects (Requires Token):

  • GET /api/v1/projects (List user's projects)
  • POST /api/v1/projects (Create project)
  • GET /api/v1/projects/{id} (View project)
  • PUT /api/v1/projects/{id} (Update project)
  • DELETE /api/v1/projects/{id} (Delete project)

Tasks (Requires Token):

  • GET /api/v1/projects/{projectid}/tasks (List tasks in a project)
  • POST /api/v1/projects/{projectid}/tasks (Add task to a project)
  • PUT /api/v1/tasks/{id} (Update specific task - *Notice it's flattened!*)
  • DELETE /api/v1/tasks/{id} (Delete specific task)

6. System Architecture (PHP Folder Structure)

A production API does not dump all code into index.php. We use MVC principles.
text
1234567891011
/api/
  ├── .htaccess             # Routes all to index.php
  ├── index.php             # Front Controller / Router
  ├── config/
  │   └── database.php      # PDO Connection
  ├── controllers/
  │   ├── AuthController.php
  │   ├── ProjectController.php
  │   └── TaskController.php
  └── helpers/
      └── Response.php      # json_encode() helper

7. Core Implementation Steps

Step 1: The Router (index.php) Initialize headers, handle CORS, parse the URL, and check the Authorization header. If a token is present, query the users table and load the $currentUser.

Step 2: Validation & Creation (POST /projects) Inside ProjectController, read php://input. Validate that "title" is not empty. If invalid, return 422 Unprocessable Entity. If valid, execute PDO: INSERT INTO projects (userid, title) VALUES (:uid, :title). Return 201 Created.

Step 3: Authorization (GET /projects/5) Inside ProjectController, fetch project #5. Check if $project['userid'] == $currentUser['id']. If they don't match, return 403 Forbidden. If they match, return 200 OK with the JSON data.

Step 4: Pagination & Filtering (GET /tasks) Inside TaskController, check for $GET['status']. Apply LIMIT and OFFSET. Return the array wrapped in a {"meta": {}, "data": []} JSON structure.

8. Putting it all together

By following these steps, you have applied:
  • Chapter 5 & 10: Perfect URL endpoint design.
  • Chapter 6 & 7: Proper HTTP methods and 200/201/403/422 status codes.
  • Chapter 9 & 18: JSON decoding, input validation, and structured error responses.
  • Chapter 14 & 17: Token authentication and resource-ownership authorization.
  • Chapter 21: Secure PDO database connections.

9. Best Practices applied

  • Statelessness: The API relies entirely on the Bearer token sent with every request; no PHP sessions are used.
  • Flattened URLs: We didn't do /projects/1/tasks/5/update. We flattened it to PUT /tasks/5 for direct manipulation.
  • Consistent Responses: Every successful request returns JSON, and every error returns a structured JSON error object.

10. Common Mistakes in Projects

  • Forgetting Foreign Key Constraints: If you delete a project, the database must automatically delete its tasks (ON DELETE CASCADE). If you forget this, your database fills up with "orphan" tasks.
  • Returning the password hash: When a user logs in or views their profile, always unset($user['passwordhash']) before passing the array to jsonencode().

11. Mini Exercises

  1. 1. Based on the database schema, write the SQL query required for the endpoint GET /api/v1/projects/3/tasks.
*(Answer: SELECT * FROM tasks WHERE project
id = 3)*

12. Coding Challenges

Challenge 1: Build this exact project! Download XAMPP, create the database tables, and try to build the 10 endpoints outlined in Section 5 using pure PHP. Use Postman to test each endpoint.

13. MCQs with Answers

Question 1

Why did we design the update endpoint as PUT /api/v1/tasks/{id} instead of PUT /api/v1/projects/{projectid}/tasks/{id}?

Question 2

When creating a project via POST /api/v1/projects, where does the API get the userid to insert into the database?

Question 3

If a user tries to delete Project #10, but Project #10 belongs to someone else, what happens?

14. Interview Questions

  • Q: Walk me through the architecture of a Task Management REST API. What do the database tables, URLs, and authentication mechanisms look like?
  • Q: Explain why a client should NEVER send their user_id in a JSON POST payload when creating a resource.
  • Q: How do you structure a raw PHP codebase to prevent index.php from becoming a 2000-line mess of code?

15. FAQs

Q: Where can I host my PHP API? A: Almost anywhere! Since we used pure PHP and MySQL, any standard shared host (HostGator, Bluehost), VPS (DigitalOcean, Linode), or Platform-as-a-Service (Heroku) will run it perfectly.

16. Summary

In Chapter 29, we executed the Capstone Project. We mapped out a complete Task Management API, architected the MySQL database, defined 11 perfectly structured REST endpoints, and reviewed the MVC file structure needed to build it in PHP. We applied validation, token authentication, and resource authorization to ensure the project is secure and production-ready.

17. Next Chapter Recommendation

Congratulations! You possess the skills of a professional backend API developer. In the final chapter, we will prepare you to pass technical interviews. Proceed to Chapter 30: REST API Interview Questions and Practice Challenges.

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: ·