Введение: почему REST API на PHP — это быстро и просто
REST (Representational State Transfer) — это архитектурный стиль, который стал стандартом для создания веб-сервисов. Многие начинающие разработчики боятся браться за реализацию API, считая это сложной задачей. На самом деле, написать полноценный REST API на PHP можно всего за 30 минут, если следовать правильной структуре.
В этом руководстве мы создадим простое, но рабочее API для управления списком задач (To-Do List). Вы научитесь обрабатывать HTTP-методы (GET, POST, PUT, DELETE), работать с JSON и строить маршрутизацию. Все примеры кода готовы к запуску.
Что вы получите после прочтения:
- Рабочий REST API на чистом PHP без фреймворков
- Понимание принципов RESTful архитектуры
- Готовую структуру для масштабирования проекта
Шаг 1: Настройка структуры проекта и базы данных
Для начала создадим простую структуру папок. Нам понадобится всего один PHP-файл для маршрутизации (index.php) и файл с настройками базы данных (config.php).
Структура проекта
rest-api-todo/
│
├── index.php (главный роутер)
├── config.php (подключение к БД)
└── .htaccess (настройка ЧПУ)
Создание базы данных MySQL
Выполните этот SQL-запрос в phpMyAdmin или через консоль:
CREATE DATABASE todo_api;
USE todo_api;
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO tasks (title) VALUES
('Изучить PHP'),
('Написать REST API'),
('Опубликовать статью');
Файл config.php
<?php
// config.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type');
$host = 'localhost';
$dbname = 'todo_api';
$username = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo json_encode(['error' => 'Ошибка подключения к БД: ' . $e->getMessage()]);
exit;
}
?>
Шаг 2: Создание единой точки входа (роутер)
В файле index.php мы реализуем маршрутизацию. Она будет обрабатывать URL и перенаправлять запросы к соответствующим функциям.
Файл index.php (полный код)
<?php
require_once 'config.php';
$method = $_SERVER['REQUEST_METHOD'];
$request = explode('/', trim($_SERVER['PATH_INFO'] ?? '/', '/'));
// Определяем ID задачи, если он передан
$id = isset($request[0]) && is_numeric($request[0]) ? (int)$request[0] : null;
// Обработка разных HTTP методов
switch($method) {
case 'GET':
if ($id) {
getTask($pdo, $id);
} else {
getTasks($pdo);
}
break;
case 'POST':
createTask($pdo);
break;
case 'PUT':
if ($id) {
updateTask($pdo, $id);
} else {
http_response_code(400);
echo json_encode(['error' => 'Не указан ID задачи']);
}
break;
case 'DELETE':
if ($id) {
deleteTask($pdo, $id);
} else {
http_response_code(400);
echo json_encode(['error' => 'Не указан ID задачи']);
}
break;
default:
http_response_code(405);
echo json_encode(['error' => 'Метод не поддерживается']);
}
// --- Реализация функций ---
function getTasks($pdo) {
$stmt = $pdo->query("SELECT * FROM tasks ORDER BY created_at DESC");
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($tasks);
}
function getTask($pdo, $id) {
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
$stmt->execute([$id]);
$task = $stmt->fetch(PDO::FETCH_ASSOC);
if ($task) {
echo json_encode($task);
} else {
http_response_code(404);
echo json_encode(['error' => 'Задача не найдена']);
}
}
function createTask($pdo) {
$data = json_decode(file_get_contents('php://input'), true);
if (!isset($data['title']) || empty(trim($data['title']))) {
http_response_code(400);
echo json_encode(['error' => 'Поле title обязательно']);
return;
}
$stmt = $pdo->prepare("INSERT INTO tasks (title) VALUES (?)");
$stmt->execute([trim($data['title'])]);
$newId = $pdo->lastInsertId();
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
$stmt->execute([$newId]);
$task = $stmt->fetch(PDO::FETCH_ASSOC);
http_response_code(201);
echo json_encode($task);
}
function updateTask($pdo, $id) {
$data = json_decode(file_get_contents('php://input'), true);
// Проверяем, существует ли задача
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
$stmt->execute([$id]);
$task = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$task) {
http_response_code(404);
echo json_encode(['error' => 'Задача не найдена']);
return;
}
$title = isset($data['title']) ? trim($data['title']) : $task['title'];
$completed = isset($data['completed']) ? (int)$data['completed'] : $task['completed'];
$stmt = $pdo->prepare("UPDATE tasks SET title = ?, completed = ? WHERE id = ?");
$stmt->execute([$title, $completed, $id]);
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
$stmt->execute([$id]);
echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
}
function deleteTask($pdo, $id) {
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = ?");
$stmt->execute([$id]);
$task = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$task) {
http_response_code(404);
echo json_encode(['error' => 'Задача не найдена']);
return;
}
$stmt = $pdo->prepare("DELETE FROM tasks WHERE id = ?");
$stmt->execute([$id]);
echo json_encode(['message' => 'Задача успешно