Разработка 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).
Расширенные примеры создания 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"}