Building a Complete RESTful Project API
# 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.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 intoindex.php. We use MVC principles.
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 toPUT /tasks/5for 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 tojsonencode().
11. Mini Exercises
-
1.
Based on the database schema, write the SQL query required for the endpoint
GET /api/v1/projects/3/tasks.
SELECT * FROM tasks WHERE projectid = 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
Why did we design the update endpoint as PUT /api/v1/tasks/{id} instead of PUT /api/v1/projects/{projectid}/tasks/{id}?
When creating a project via POST /api/v1/projects, where does the API get the userid to insert into the database?
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_idin a JSON POST payload when creating a resource.
-
Q: How do you structure a raw PHP codebase to prevent
index.phpfrom becoming a 2000-line mess of code?