Building a REST API
Create a JSON API with proper HTTP methods and status codes
Learn how to build a RESTful JSON API using DALT.PHP. You'll create endpoints for managing tasks with proper HTTP methods, status codes, and JSON responses.
What You'll Build
A task management API with:
GET /api/tasks- List all tasksGET /api/tasks/\{id\}- Get single taskPOST /api/tasks- Create new taskPATCH /api/tasks/\{id\}- Update taskDELETE /api/tasks/\{id\}- Delete task
All responses will be JSON with appropriate HTTP status codes.
Prerequisites
- DALT.PHP installed and running
- Basic understanding of REST APIs
- Familiarity with JSON
Time Required: 20-30 minutes
Step 1: Create the Database Table
Generate Migration
php artisan make:migration create_tasks_tableWrite the SQL
Open the migration file and add:
-- Migration: create_tasks_table
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT,
completed BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_tasks_completed ON tasks(completed);Run Migration
php artisan migrateStep 2: Create API Helper Functions
Create helper functions for JSON responses.
Create framework/Core/api.php:
<?php
function json_response($data, $status = 200)
{
http_response_code($status);
header('Content-Type: application/json');
echo json_encode($data);
exit;
}
function json_error($message, $status = 400)
{
json_response(['error' => $message], $status);
}
function json_success($data, $status = 200)
{
json_response(['success' => true, 'data' => $data], $status);
}
function json_input()
{
$input = file_get_contents('php://input');
return json_decode($input, true) ?? [];
}Then require it in framework/Core/functions.php:
require __DIR__ . '/api.php';Step 3: Create API Controllers
Create controllers for each API endpoint.
Create Directory
mkdir -p app/Http/controllers/api/tasksIndex Controller (GET /api/tasks)
Create app/Http/controllers/api/tasks/index.php:
<?php
$db = App::resolve(Core\Database::class);
$tasks = $db->query('SELECT * FROM tasks ORDER BY created_at DESC')->get();
json_success($tasks);Show Controller (GET /api/tasks/{id})
Create app/Http/controllers/api/tasks/show.php:
<?php
$db = App::resolve(Core\Database::class);
$task = $db->query('SELECT * FROM tasks WHERE id = ?', [$_GET['id']])->find();
if (!$task) {
json_error('Task not found', 404);
}
json_success($task);Store Controller (POST /api/tasks)
Create app/Http/controllers/api/tasks/store.php:
<?php
$db = App::resolve(Core\Database::class);
$input = json_input();
// Validate
if (empty($input['title'])) {
json_error('Title is required', 422);
}
// Insert
$db->query(
'INSERT INTO tasks (title, description, completed) VALUES (?, ?, ?)',
[
$input['title'],
$input['description'] ?? null,
isset($input['completed']) ? 1 : 0
]
);
// Get created task
$id = $db->connection->lastInsertId();
$task = $db->query('SELECT * FROM tasks WHERE id = ?', [$id])->find();
json_success($task, 201);Update Controller (PATCH /api/tasks/{id})
Create app/Http/controllers/api/tasks/update.php:
<?php
$db = App::resolve(Core\Database::class);
$input = json_input();
// Check if task exists
$task = $db->query('SELECT * FROM tasks WHERE id = ?', [$_GET['id']])->find();
if (!$task) {
json_error('Task not found', 404);
}
// Validate
if (isset($input['title']) && empty($input['title'])) {
json_error('Title cannot be empty', 422);
}
// Update
$db->query(
'UPDATE tasks SET
title = COALESCE(?, title),
description = COALESCE(?, description),
completed = COALESCE(?, completed),
updated_at = CURRENT_TIMESTAMP
WHERE id = ?',
[
$input['title'] ?? null,
$input['description'] ?? null,
isset($input['completed']) ? ($input['completed'] ? 1 : 0) : null,
$_GET['id']
]
);
// Get updated task
$task = $db->query('SELECT * FROM tasks WHERE id = ?', [$_GET['id']])->find();
json_success($task);Destroy Controller (DELETE /api/tasks/{id})
Create app/Http/controllers/api/tasks/destroy.php:
<?php
$db = App::resolve(Core\Database::class);
// Check if task exists
$task = $db->query('SELECT * FROM tasks WHERE id = ?', [$_GET['id']])->find();
if (!$task) {
json_error('Task not found', 404);
}
// Delete
$db->query('DELETE FROM tasks WHERE id = ?', [$_GET['id']]);
json_success(['message' => 'Task deleted successfully']);Step 4: Add API Routes
Register all API routes in routes/routes.php:
<?php
global $router;
// Existing routes
$router->get('/', 'welcome.php');
// API routes
$router->get('/api/tasks', 'api/tasks/index.php');
$router->get('/api/tasks/\{id\}', 'api/tasks/show.php');
$router->post('/api/tasks', 'api/tasks/store.php');
$router->patch('/api/tasks/\{id\}', 'api/tasks/update.php');
$router->delete('/api/tasks/\{id\}', 'api/tasks/destroy.php');Step 5: Test Your API
Start the server and test all endpoints.
Start Server
php artisan serveTest GET /api/tasks (List All)
curl http://localhost:8000/api/tasksResponse:
{
"success": true,
"data": []
}Test POST /api/tasks (Create)
curl -X POST http://localhost:8000/api/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Buy groceries","description":"Milk, eggs, bread"}'Response:
{
"success": true,
"data": {
"id": 1,
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": 0,
"created_at": "2024-03-15 12:00:00",
"updated_at": "2024-03-15 12:00:00"
}
}Test GET /api/tasks/{id} (Get One)
curl http://localhost:8000/api/tasks/1Response:
{
"success": true,
"data": {
"id": 1,
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": 0,
"created_at": "2024-03-15 12:00:00",
"updated_at": "2024-03-15 12:00:00"
}
}Test PATCH /api/tasks/{id} (Update)
curl -X PATCH http://localhost:8000/api/tasks/1 \
-H "Content-Type: application/json" \
-d '{"completed":true}'Response:
{
"success": true,
"data": {
"id": 1,
"title": "Buy groceries",
"description": "Milk, eggs, bread",
"completed": 1,
"created_at": "2024-03-15 12:00:00",
"updated_at": "2024-03-15 12:05:00"
}
}Test DELETE /api/tasks/{id} (Delete)
curl -X DELETE http://localhost:8000/api/tasks/1Response:
{
"success": true,
"data": {
"message": "Task deleted successfully"
}
}What You Learned
Congratulations! You've built a complete REST API. Here's what you learned:
1. RESTful Design
GET /api/tasks → List all tasks
GET /api/tasks/\{id\} → Get single task
POST /api/tasks → Create task
PATCH /api/tasks/\{id\} → Update task
DELETE /api/tasks/\{id\} → Delete taskEach endpoint uses the appropriate HTTP method.
2. HTTP Status Codes
200 OK- Successful GET, PATCH, DELETE201 Created- Successful POST404 Not Found- Resource doesn't exist422 Unprocessable Entity- Validation error
3. JSON Responses
json_success($data, 200); // Success response
json_error($message, 404); // Error responseConsistent response format makes the API easy to consume.
4. Request Body Parsing
$input = json_input(); // Parse JSON from request bodyAPIs receive data as JSON, not form data.
5. Validation
if (empty($input['title'])) {
json_error('Title is required', 422);
}Always validate input before saving to database.
6. Partial Updates (PATCH)
UPDATE tasks SET
title = COALESCE(?, title), // Only update if provided
description = COALESCE(?, description)
WHERE id = ?PATCH allows updating only specific fields.