Как написать REST API на PHP за 30 минут: пошаговое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем вам REST API на PHP?

REST API (Representational State Transfer) — это архитектурный стиль, который позволяет разным приложениям общаться друг с другом через HTTP. Сегодня без API не обходится ни один современный веб-сервис: мобильные приложения, SPA-фронтенды, интеграции с платежными системами — всё это требует быстрого и понятного интерфейса для обмена данными.

PHP остаётся одним из самых популярных языков для бэкенда. Вы можете написать полноценный REST API на чистом PHP без громоздких фреймворков — это займёт у вас не больше 30 минут. В этой статье мы разберём практический пример с CRUD-операциями (создание, чтение, обновление, удаление) для управления списком задач (To-Do).

1. Подготовка окружения и структура проекта

Для работы вам понадобится:

  • Локальный сервер (Open Server, XAMPP, MAMP или встроенный PHP-сервер)
  • PHP версии 7.4 или выше
  • Редактор кода (VS Code, PhpStorm)

Создайте корневую папку rest-api-php и внутри неё файлы:

rest-api-php/
├── index.php       (точка входа, маршрутизатор)
├── config.php      (настройки базы данных)
├── api/
│   ├── tasks.php   (CRUD для задач)
│   └── helpers.php (вспомогательные функции)
└── .htaccess       (перенаправление запросов на index.php)

1.1. Настройка .htaccess для красивых URL

Чтобы все запросы направлялись в единую точку входа, создайте файл .htaccess в корне:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Если используете встроенный сервер PHP, просто запустите его из папки проекта: php -S localhost:8000.

2. Создание маршрутизатора и базового API

Откройте index.php — это наш главный обработчик. Он будет анализировать HTTP-метод и URI вызывать нужные функции.

2.1. index.php — точка входа

<?php
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

require_once 'config.php';
require_once 'api/helpers.php';

$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = rtrim($uri, '/');

// Простая маршрутизация
if ($uri === '/api/tasks') {
    require_once 'api/tasks.php';
    handleTasks($method);
} elseif (preg_match('/^\/api\/tasks\/(\d+)$/', $uri, $matches)) {
    require_once 'api/tasks.php';
    handleTask($method, (int)$matches[1]);
} else {
    sendResponse(['error' => 'Endpoint not found'], 404);
}
?>

Мы обрабатываем два маршрута: /api/tasks (список/создание) и /api/tasks/{id} (конкретная задача).

2.2. helpers.php — вспомогательные функции

<?php
function sendResponse($data, $status = 200) {
    http_response_code($status);
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

function getJsonInput() {
    $input = file_get_contents('php://input');
    return json_decode($input, true) ?? [];
}
?>

3. Работа с базой данных и CRUD-операции

Создадим простую таблицу tasks в MySQL:

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    status ENUM('pending', 'completed') DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Файл config.php:

<?php
$host = 'localhost';
$dbname = 'rest_api_db';
$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) {
    sendResponse(['error' => 'Database connection failed: ' . $e->getMessage()], 500);
}
?>

3.1. tasks.php — основная логика API

Здесь мы реализуем все CRUD-операции. Функция handleTasks отвечает за GET (список) и POST (создание), а handleTask — за GET/{id}, PUT (обновление) и DELETE.

<?php
function handleTasks($method) {
    global $pdo;

    if ($method === 'GET') {
        $stmt = $pdo->query("SELECT * FROM tasks ORDER BY created_at DESC");
        $tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
        sendResponse($tasks);
    } 
    elseif ($method === 'POST') {
        $data = getJsonInput();
        if (empty($data['title'])) {
            sendResponse(['error' => 'Title is required'], 400);
        }
        $stmt = $pdo->prepare("INSERT INTO tasks (title) VALUES (:title)");
        $stmt->execute(['title' => $data['title']]);
        $id = $pdo->lastInsertId();
        sendResponse(['id' => $id, 'message' => 'Task created'], 201);
    } 
    else {
        sendResponse(['error' => 'Method not allowed'], 405);
    }
}

function handleTask($method, $id) {
    global $pdo;

    if ($method === 'GET') {
        $stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = :id");
        $stmt->execute(['id' => $id]);
        $task = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$task) {
            sendResponse(['error' => 'Task not found'], 404);
        }
        sendResponse($task);
    } 
    elseif ($method === 'PUT') {
        $data = getJsonInput();
        $fields = [];
        $params = ['id' => $id];
        if (isset($data['title'])) {
            $fields[] = 'title = :title';
            $params['title'] = $data['title'];
        }
        if (isset($data['status'])) {
            $fields[] = 'status = :status';
            $params['status'] = $data['status'];
        }
        if (empty($fields)) {
            sendResponse(['error' => 'No fields                

Блоги

Рекомендаций по книгам