REST API — это как официант в ресторане: вы делаете заказ, он передаёт его на кухню и приносит вам готовое блюдо. Только в мире веба официант — это ваш сервер, а блюда — данные. Если вы хотите, чтобы ваше PHP-приложение могло общаться с мобильными приложениями, фронтендом или другими сервисами, вам нужно REST API. В этой статье мы шаг за шагом создадим простое, но полноценное API на чистом PHP, без фреймворков, чтобы вы поняли, как всё работает под капотом.

Digital-студия WNDER

Что такое REST API и зачем он нужен

REST (Representational State Transfer) — это архитектурный стиль, который описывает, как клиент и сервер обмениваются данными. В REST API мы работаем с ресурсами (например, пользователями, товарами, заказами) через стандартные HTTP-методы: GET (получить), POST (создать), PUT/PATCH (обновить), DELETE (удалить).

Главное преимущество REST — простота и универсальность. Ваше API сможет использовать любое приложение: веб-сайт на React, мобильное приложение на Swift или другой сервер на Python. Данные обычно передаются в формате JSON — он лёгкий и понятный.

Зачем писать своё API? Например, у вас есть интернет-магазин на PHP, и вы хотите сделать мобильное приложение. Вместо того чтобы дублировать логику, вы создаёте API, которое возвращает данные о товарах, и приложение их отображает.

Планирование структуры API

Прежде чем писать код, определитесь с ресурсами и эндпоинтами (URL-адресами). Например, для управления пользователями:

  • GET /users — получить список всех пользователей
  • GET /users/{id} — получить одного пользователя по ID
  • POST /users — создать нового пользователя
  • PUT /users/{id} — обновить пользователя
  • DELETE /users/{id} — удалить пользователя

Такой подход называется ресурсно-ориентированным. Старайтесь использовать существительные во множественном числе и избегайте глаголов в URL (например, не /getUsers, а /users).

Правило: Всегда возвращайте правильные HTTP-статусы. 200 — успех, 201 — создано, 400 — неверный запрос, 404 — не найдено, 500 — ошибка сервера. Это помогает клиенту понять, что произошло.

Создание основы: маршрутизация и обработка запросов

Начнём с простого фронт-контроллера — файла index.php, который будет принимать все запросы. Для этого настроим .htaccess (если используете Apache), чтобы все запросы перенаправлялись на index.php.

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

Теперь в index.php мы можем получить URI запроса и метод.

<?php
// index.php
header('Content-Type: application/json; charset=utf-8');

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

// Простая маршрутизация
switch (true) {
    case $path === 'users' && $method === 'GET':
        getUsers();
        break;
    case preg_match('/^users\/(\d+)$/', $path, $matches) && $method === 'GET':
        getUser($matches[1]);
        break;
    case $path === 'users' && $method === 'POST':
        createUser();
        break;
    case preg_match('/^users\/(\d+)$/', $path, $matches) && $method === 'PUT':
        updateUser($matches[1]);
        break;
    case preg_match('/^users\/(\d+)$/', $path, $matches) && $method === 'DELETE':
        deleteUser($matches[1]);
        break;
    default:
        http_response_code(404);
        echo json_encode(['error' => 'Not Found']);
}

Это минимальная маршрутизация. В реальном проекте лучше использовать готовые библиотеки (например, FastRoute), но для понимания сути этого достаточно.

Работа с данными: CRUD-операции

Теперь реализуем функции для работы с пользователями. Для примера будем хранить данные в массиве (в реальном проекте — в базе данных).

// Хранилище (заглушка)
$users = [
    1 => ['id' => 1, 'name' => 'Иван', 'email' => 'ivan@example.com'],
    2 => ['id' => 2, 'name' => 'Мария', 'email' => 'maria@example.com'],
];

function getUsers() {
    global $users;
    echo json_encode(array_values($users));
}

function getUser($id) {
    global $users;
    if (isset($users[$id])) {
        echo json_encode($users[$id]);
    } else {
        http_response_code(404);
        echo json_encode(['error' => 'User not found']);
    }
}

function createUser() {
    global $users;
    $input = json_decode(file_get_contents('php://input'), true);
    if (empty($input['name']) || empty($input['email'])) {
        http_response_code(400);
        echo json_encode(['error' => 'Name and email required']);
        return;
    }
    $newId = max(array_keys($users)) + 1;
    $users[$newId] = [
        'id' => $newId,
        'name' => $input['name'],
        'email' => $input['email']
    ];
    http_response_code(201);
    echo json_encode($users[$newId]);
}

function updateUser($id) {
    global $users;
    if (!isset($users[$id])) {
        http_response_code(404);
        echo json_encode(['error' => 'User not found']);
        return;
    }
    $input = json_decode(file_get_contents('php://input'), true);
    if (isset($input['name'])) $users[$id]['name'] = $input['name'];
    if (isset($input['email'])) $users[$id]['email'] = $input['email'];
    echo json_encode($users[$id]);
}

function deleteUser($id) {
    global $users;
    if (isset($users[$id])) {
        unset($users[$id]);
        http_response_code(204);
    } else {
        http_response_code(404);
        echo json_encode(['error' => 'User not found']);
    }
}

Обратите внимание: для POST и PUT мы читаем тело запроса через php://input и декодируем JSON. Для DELETE возвращаем 204 (No Content), если удаление успешно.

Обработка ошибок и безопасность

Любое API должно корректно обрабатывать ошибки. Не выдавайте пользователю стек вызовов или SQL-запросы — это небезопасно. Возвращайте понятные сообщения и правильные статусы.

Также не забывайте про безопасность:

  • Всегда проверяйте входящие данные (валидация).
  • Используйте HTTPS, чтобы данные не перехватили.
  • Для аутентификации можно применять токены (JWT, OAuth).
  • Ограничивайте методы запросов (например, разрешайте только GET и POST для публичных эндпоинтов).
Лайфхак: Добавьте глобальный обработчик исключений, чтобы в случае ошибки возвращался JSON, а не HTML. Например: set_exception_handler(function($e) { http_response_code(500); echo json_encode(['error' => 'Internal Server Error']); });

Вот пример обработки ошибок с помощью try-catch:

try {
    // ваш код
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
}

Тестирование API

После написания кода нужно проверить, что всё работает. Самый простой способ — использовать curl или инструменты вроде Postman.

Пример запроса через curl для получения списка пользователей:

// Пример на JavaScript (fetch)
fetch('http://localhost/api/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Или через curl в командной строке:

// Не PHP, но полезно знать
// curl -X GET http://localhost/api/users

Проверьте все эндпоинты: создание, чтение, обновление, удаление. Убедитесь, что статусы и данные соответствуют ожиданиям.

Что в итоге

Мы создали простое REST API на чистом PHP, которое умеет обрабатывать CRUD-операции, возвращать JSON и корректные HTTP-статусы. Конечно, в реальном проекте стоит использовать фреймворк (Laravel, Symfony) или хотя бы библиотеку для маршрутизации, но понимание основ поможет вам принимать правильные решения.

Главное — не бойтесь экспериментировать. Начните с малого, добавьте базу данных, аутентификацию, кэширование. API — это мощный инструмент, который открывает двери для интеграций.

Удачи в разработке!

Студия WNDER