Разработка REST API на PHP: фреймворки и примеры

Раздел:

Основные подходы к созданию API на PHP

Для быстрой и эффективной разработки REST API на PHP рекомендуется использовать микрофреймворк Slim 4. Он предоставляет удобную маршрутизацию, поддержку middleware и лёгкую архитектуру, что позволяет сосредоточиться на бизнес-логике.

Установка выполняется через Composer:

composer require slim/slim:^4.12
composer require slim/psr7

обработка php (обработка данных в php)

Создадим простой endpoint, возвращающий список пользователей в формате JSON:

<?php
use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

require __DIR__ . '/vendor/autoload.php';

$app = AppFactory::create();

$app->get('/api/users', function (Request $request, Response $response) {
    $users = ['Alice', 'Bob', 'Charlie'];
    $payload = json_encode($users);
    $response->getBody()->write($payload);
    return $response->withHeader('Content-Type', 'application/json');
});

$app->run();

Php learning (обучение php)

После запуска встроенного сервера (php -S localhost:8080 -t public/) запрос GET /api/users вернёт массив имён. Slim автоматически обрабатывает HTTP-методы, параметры пути и middleware.

Дополнительно можно добавить обработку ошибок, CORS-заголовки и валидацию через middleware. Slim активно используется в микросервисной архитектуре и простых API.

Как создать простое API на чистом PHP без фреймворков?

Для минималистичных проектов или учебных целей можно обойтись без фреймворка, используя суперглобальные переменные $_SERVER и $_REQUEST.

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');

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

if ($method === 'GET' && $path === '/api/users') {
    $users = ['Alice', 'Bob'];
    echo json_encode($users);
} elseif ($method === 'POST' && $path === '/api/users') {
    $data = json_decode(file_get_contents('php://input'), true);
    // (сохранение в БД опущено)
    echo json_encode(['status' => 'created']);
} else {
    http_response_code(404);
    echo json_encode(['error' => 'Not Found']);
}

Php учебник (учебник по php)

Типичные ошибки и их решения:

  • Отсутствие заголовка Content-Type – ответ не воспринимается как JSON. Всегда устанавливать header('Content-Type: application/json').
  • Неправильная обработка маршрутов – при множестве маршрутов код становится нечитаемым. Рекомендуется использовать switch или собственный роутер.
  • Проблемы с CORS – при запросах с другого домена браузер блокирует ответ. Добавлять заголовки Access-Control-Allow-Origin и обрабатывать preflight-запросы (OPTIONS).
  • Уязвимости SQL-инъекций при работе с БД – использовать PDO с подготовленными запросами.

Как использовать Laravel для создания полнофункционального API?

Laravel предоставляет богатый инструментарий для API: контроллеры, Eloquent ORM, пагинацию, аутентификацию через Laravel Sanctum и автоматическое формирование ответов JSON.

// routes/api.php
use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index']);
Route::post('/users', [UserController::class, 'store']);
Route::get('/users/{id}', [UserController::class, 'show']);

// app/Http/Controllers/UserController.php
public function index()
{
    $users = User::all();
    return response()->json($users);
}

public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users'
    ]);
    $user = User::create($validated);
    return response()->json($user, 201);
}

Apis php (api на php)

Типичные проблемы:

  • Избыточность при создании простого API – Laravel «тяжёлый» для микросервисов. Использовать Lumen или отключать ненужные сервисы через config/app.php.
  • Медленная работа из-за большого количества middleware. Оптимизировать через кэширование конфигурации и маршрутов (php artisan optimize).
  • Сложность обработки исключений – не возвращаются корректные JSON-ошибки. Настроить ExceptionHandler или использовать ApiResponse макросы.

Как реализовать API с помощью Lumen?

Lumen – микрофреймворк от создателей Laravel, оптимизированный для быстрых API. Он имеет ту же экосистему, но с урезанным функционалом (нет сессий, представлений, Artisan-команд многих команд).

// routes/web.php
$router->get('/api/items', function () {
    return response()->json(['item1', 'item2']);
});

$router->post('/api/items', function (Illuminate\Http\Request $request) {
    // обработка данных
    return response()->json(['status' => 'stored'], 201);
});

Ошибки и их решения:

  • Отсутствие некоторых возможностей Laravel (например, миграций с помощью Artisan) – установить полный Laravel, если требуется консоль.
  • По умолчанию Lumen не загружает фасады и Eloquent. Включить через $app->withFacades(); $app->withEloquent(); в bootstrap/app.php.
  • Проблемы с кэшированием – кэш конфигурации нужно создавать через команду php artisan config:cache, но в Lumen она отсутствует (реализовать вручную или перейти на Laravel).
- Index php post (обработка post-запросов в php)
- Index php page ru (создание index.php страницы)
- Php javascript css (javascript и css в php)

Расширенные примеры создания API на PHP

Представлены продвинутые сценарии: полноценный CRUD с базой данных, обработка ошибок и аутентификация JWT на примере Slim 4.

Пример 1: CRUD с использованием Slim и PDO

Реализуем endpoints для работы с таблицей products через PDO. Для наглядности используем SQLite.

Пример
<?php
use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

require __DIR__ . '/vendor/autoload.php';

$db = new PDO('sqlite:db.sqlite');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec('CREATE TABLE IF NOT EXISTS products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, price REAL)');

$app = AppFactory::create();

// Получение всех товаров
$app->get('/api/products', function (Request $request, Response $response) use ($db) {
    $stmt = $db->query('SELECT * FROM products');
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $payload = json_encode($products);
    $response->getBody()->write($payload);
    return $response->withHeader('Content-Type', 'application/json');
});

// Создание товара
$app->post('/api/products', function (Request $request, Response $response) use ($db) {
    $data = $request->getParsedBody();
    $stmt = $db->prepare('INSERT INTO products (name, price) VALUES (?, ?)');
    $stmt->execute([$data['name'], $data['price']]);
    $id = $db->lastInsertId();
    $product = ['id' => (int)$id, 'name' => $data['name'], 'price' => (float)$data['price']];
    $response->getBody()->write(json_encode($product));
    return $response->withHeader('Content-Type', 'application/json')->withStatus(201);
});

// Обновление товара
$app->put('/api/products/{id}', function (Request $request, Response $response, array $args) use ($db) {
    $data = $request->getParsedBody();
    $stmt = $db->prepare('UPDATE products SET name = ?, price = ? WHERE id = ?');
    $stmt->execute([$data['name'], $data['price'], $args['id']]);
    if ($stmt->rowCount()) {
        $product = ['id' => (int)$args['id'], 'name' => $data['name'], 'price' => (float)$data['price']];
        $response->getBody()->write(json_encode($product));
        return $response->withHeader('Content-Type', 'application/json');
    }
    return $response->withStatus(404)->withBody(json_encode(['error' => 'Not found']));
});

// Удаление товара
$app->delete('/api/products/{id}', function (Request $request, Response $response, array $args) use ($db) {
    $stmt = $db->prepare('DELETE FROM products WHERE id = ?');
    $stmt->execute([$args['id']]);
    if ($stmt->rowCount()) {
        return $response->withStatus(204);
    }
    return $response->withStatus(404);
});

$app->run();

Тестирование с помощью curl:

curl -X POST http://localhost:8080/api/products -d '{"name":"Laptop","price":1500}' -H "Content-Type: application/json"
{"id":1,"name":"Laptop","price":1500}
curl http://localhost:8080/api/products
[{"id":1,"name":"Laptop","price":1500}]

Пример 2: Централизованная обработка ошибок через middleware

Создадим middleware, который перехватывает исключения и возвращает JSON с кодом ошибки.

Пример
<?php
use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response as SlimResponse;

require __DIR__ . '/vendor/autoload.php';

$app = AppFactory::create();

// Middleware для обработки исключений
$errorMiddleware = function (Request $request, RequestHandler $handler) {
    try {
        return $handler->handle($request);
    } catch (\Exception $e) {
        $response = new SlimResponse();
        $payload = json_encode(['error' => $e->getMessage()]);
        $response->getBody()->write($payload);
        return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
    }
};

$app->add($errorMiddleware);

$app->get('/api/error', function (Request $request, Response $response) {
    throw new \Exception('Something went wrong');
});

$app->run();

Результат при запросе GET /api/error:

{"error":"Something went wrong"}

Пример 3: JWT-аутентификация с middleware

Используем библиотеку firebase/php-jwt для создания и проверки токенов. Определим middleware, который проверяет токен в заголовке Authorization.

Пример
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Factory\AppFactory;
use Slim\Psr7\Response as SlimResponse;

require __DIR__ . '/vendor/autoload.php';

$app = AppFactory::create();
$secretKey = 'your-secret-key';

// Middleware авторизации
$authMiddleware = function (Request $request, RequestHandler $handler) use ($secretKey) {
    $authHeader = $request->getHeaderLine('Authorization');
    if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) {
        $response = new SlimResponse();
        $response->getBody()->write(json_encode(['error' => 'Unauthorized']));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(401);
    }
    $token = substr($authHeader, 7);
    try {
        $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
        $request = $request->withAttribute('user_id', $decoded->sub);
    } catch (\Exception $e) {
        $response = new SlimResponse();
        $response->getBody()->write(json_encode(['error' => 'Invalid token']));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(401);
    }
    return $handler->handle($request);
};

// Маршрут для получения токена (упрощённый)
$app->post('/api/auth/login', function (Request $request, Response $response) use ($secretKey) {
    $payload = [
        'sub' => 123,
        'iat' => time(),
        'exp' => time() + 3600
    ];
    $token = JWT::encode($payload, $secretKey, 'HS256');
    $response->getBody()->write(json_encode(['token' => $token]));
    return $response->withHeader('Content-Type', 'application/json');
});

// Защищённый endpoint
$app->get('/api/profile', function (Request $request, Response $response) {
    $userId = $request->getAttribute('user_id');
    $payload = json_encode(['user_id' => $userId, 'name' => 'John']);
    $response->getBody()->write($payload);
    return $response->withHeader('Content-Type', 'application/json');
})->add($authMiddleware);

$app->run();

Результат: после вызова POST /api/auth/login получаем токен. Затем запрос GET /api/profile с заголовком Authorization: Bearer <token> возвращает данные пользователя.

curl -X POST http://localhost:8080/api/auth/login
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."}

curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." http://localhost:8080/api/profile
{"user_id":123,"name":"John"}

API на PHP - comments

En
Apis php (php)