Project final - REST API
Combine all parts and finalize a working REST API.
Combining all parts
In the final lesson you combine every part. Router, addRoute, dispatch and JsonResponse are ready. Now you'll write four handlers: handleGet returns the task list, handlePost creates a task, handlePut updates one and handleDelete deletes one.
Then the runRestApi() function creates a Router instance, registers the four routes, sets the $_SERVER values by hand and runs the request through dispatch. The returned JsonResponse object's send() method writes the structured data.
Error responses
APIs must report errors consistently too. An unknown path or method answers with 404; the body carries an error message. A missing or broken body answers with 400.
Every error response is also a JsonResponse instance, so success and error responses share the same shape. The client handles every case with a single parser.
Exercise Write the runRestApi function
Write a runRestApi() function. Inside it create a new Router and add four routes with addRoute: GET /tasks, POST /tasks, PUT /tasks/1, DELETE /tasks/1 — handlers are "handleGet", "handlePost", "handlePut", "handleDelete" in order. Then set $_SERVER["REQUEST_METHOD"] = "GET"; and $_SERVER["PATH_INFO"] = "/tasks";, run the request with dispatch and return the send() output of the resulting JsonResponse object.
Show example solution
string { ... }. Start with $router = new Router();. Make four $router->addRoute(...) calls. Set $_SERVER["REQUEST_METHOD"] = "GET"; and $_SERVER["PATH_INFO"] = "/tasks";. Run with $response = $router->dispatch($_SERVER["REQUEST_METHOD"], $_SERVER["PATH_INFO"]); and return $response->send();.
Example solution:
<?php
// REST API project: all parts combined — write the runRestApi demo
class Router {
public array $routes = [];
public function addRoute(string $method, string $path, $handler): void {
$this->routes[] = ["method" => $method, "path" => $path, "handler" => $handler];
}
public function dispatch(string $method, string $path) {
foreach ($this->routes as $route) {
if ($route["method"] === $method && $route["path"] === $path) {
return ($route["handler"])();
}
}
return "404 Not Found";
}
}
class JsonResponse {
public int $status;
public array $body;
public function __construct(int $status, array $body) {
$this->status = $status;
$this->body = $body;
}
public function send(): string {
http_response_code($this->status);
header("Content-Type: application/json");
return json_encode($this->body, JSON_UNESCAPED_UNICODE);
}
}
function handleGet(): JsonResponse {
return new JsonResponse(200, ["tasks" => [["id" => 1, "title" => "First task"]]]);
}
function handlePost(): JsonResponse {
return new JsonResponse(201, ["message" => "Created"]);
}
function handlePut(): JsonResponse {
return new JsonResponse(200, ["message" => "Updated"]);
}
function handleDelete(): JsonResponse {
return new JsonResponse(200, ["message" => "Deleted"]);
}
function runRestApi(): string {
$router = new Router();
$router->addRoute("GET", "/tasks", "handleGet");
$router->addRoute("POST", "/tasks", "handlePost");
$router->addRoute("PUT", "/tasks/1", "handlePut");
$router->addRoute("DELETE", "/tasks/1", "handleDelete");
$_SERVER["REQUEST_METHOD"] = "GET";
$_SERVER["PATH_INFO"] = "/tasks";
$response = $router->dispatch($_SERVER["REQUEST_METHOD"], $_SERVER["PATH_INFO"]);
return $response->send();
}
// Demo:
echo runRestApi();
Test yourself
-
Complete the request path
$_SERVER["____"]Show answer
$_SERVER["PATH_INFO"] -
Match the handlers
- handleGet
- Lists
- handlePost
- Creates
- handlePut
- Updates
- handleDelete
- Deletes
-
Which status should handlePost return when it creates a new resource?
- 201 Created
- 200 OK
- 404 Not Found
- 400 Bad Request
Show answer
201 Created — Correct. Creating a new resource is reported with 201; 200 is a successful read of an existing record.