REST API — это архитектурный стиль для построения веб-сервисов, использующий HTTP-методы (GET, POST, PUT, DELETE) для работы с ресурсами. В этой статье мы создадим полноценный REST API на чистом PHP без фреймворков.
Структура проекта
rest-api/
├── src/
│ ├── Config/
│ │ └── Database.php
│ ├── Controllers/
│ │ ├── UserController.php
│ │ └── ProductController.php
│ ├── Models/
│ │ ├── UserModel.php
│ │ └── ProductModel.php
│ └── Middleware/
│ └── AuthMiddleware.php
├── public/
│ └── index.php
└── .htaccess
Маршрутизация (Router)
Создаём простой маршрутизатор, который парсит URI и вызывает нужный контроллер:
routes[method][
path]=handler;
public function dispatch(string
method,stringuri): mixed {
foreach (
this−>routes[method] ?? [] as
path=>handler) {
path);
pattern . '#';
if (preg_match(pattern,
uri,matches)) {
array_shift(matches);
[controller,
action]=handler;
controllerInstance=newcontroller();
return
controllerInstance−>action(...matches);
http_response_code(404);
echo json_encode(['error' => 'Route not found']);
return null;
?>
Точка входа (public/index.php)
<?php
require __DIR__ . '/../vendor/autoload.php';
use App\Router\Router;
use App\Controllers\UserController;
use App\Controllers\ProductController;
use App\Middleware\AuthMiddleware;
header('Content-Type: application/json');
router = new Router();
// Публичные маршруты
router->add('POST', '/api/auth/login', [UserController::class, 'login']);
router->add('POST', '/api/auth/register', [UserController::class, 'register']);
// Защищённые маршруты (с JWT)
router->add('GET', '/api/users', [UserController::class, 'index']);
router->add('GET', '/api/users/{id}', [UserController::class, 'show']);
router->add('POST', '/api/users', [UserController::class, 'create']);
router->add('PUT', '/api/users/{id}', [UserController::class, 'update']);
router->add('DELETE', '/api/users/{id}', [UserController::class, 'delete']);
router->add('GET', '/api/products', [ProductController::class, 'index']);
router->add('POST', '/api/products', [ProductController::class, 'create']);
method = _SERVER['REQUEST_METHOD'];
uri = parse_url(_SERVER['REQUEST_URI'], PHP_URL_PATH);
// Проверка JWT для защищённых маршрутов
protectedRoutes = ['/api/users', '/api/products'];
foreach (
protectedRoutesasroute) {
if (str_starts_with(
uri,route) && method !== 'POST') {
headers = getallheaders();
auth = new AuthMiddleware();
auth->validate(headers['Authorization'] ?? '');
break;
router->dispatch(
method,uri);
?>
Контроллер UserController
userModel = new UserModel();
this->jwtService = new JwtService();
public function index(): void {
users=this->userModel->getAll();
echo json_encode(users);
public function show(int id): void {
user=this->userModel->getById(id);
if (!user) {
http_response_code(404);
echo json_encode(['error' => 'User not found']);
return;
echo json_encode(user);
public function create(): void {
data = json_decode(file_get_contents('php://input'), true);
id=this->userModel->create(data);
http_response_code(201);
echo json_encode(['id' => id]);
public function update(int id): void {
data = json_decode(file_get_contents('php://input'), true);
this−>userModel−>update(id, data);
echo json_encode(['success' => true]);
public function delete(int id): void {
this−>userModel−>delete(id);
echo json_encode(['success' => true]);
public function login(): void {
data = json_decode(file_get_contents('php://input'), true);
user =
this−>userModel−>findByEmail(data['email']);
if (!
user∣∣!password
erify(data['password'], user['password'])) {
http_response_code(401);
echo json_encode(['error' => 'Invalid credentials']);
return;
token =
this−>jwtService−>generate([
id
=>user['id'], 'email' => user['email']]);
echo json_encode(['token' => token]);
public function register(): void {
data = json_decode(file_get_contents('php://input'), true);
data['password'] = password_hash(data['password'], PASSWORD_BCRYPT);
id =
this−>userModel−>create(data);
http_response_code(201);
echo json_encode(['id' => id]);
?>
Модель UserModel
<?php
namespace App\Models;
use App\Config\Database;
class UserModel {
private \PDO db;
public function __construct() {
this->db = Database::getConnection();
public function getAll(): array {
stmt = this->db->query('SELECT id, name, email, created_at FROM users');
return stmt->fetchAll(\PDO::FETCH_ASSOC);
public function getById(int id): array|false {
stmt = this->db->prepare('SELECT id, name, email, created_at FROM users WHERE id = ?');
stmt->execute([id]);
return stmt->fetch(\PDO::FETCH_ASSOC);
public function create(array data): int {
stmt = this->db->prepare('INSERT INTO users (name, email, password) VALUES (?, ?, ?)');
stmt->execute([
data[
name
],data['email'], data['password']]);
return (int) this->db->lastInsertId();
public function update(int
id,arraydata): void {
stmt=this->db->prepare('UPDATE users SET name = ?, email = ? WHERE id = ?');
stmt−>execute([data['name'],
data[
email
],id]);
public function delete(int id): void {
stmt = this->db->prepare('DELETE FROM users WHERE id = ?');
stmt->execute([id]);
public function findByEmail(string email): array|false {
stmt=this->db->prepare('SELECT * FROM users WHERE email = ?');
stmt−>execute([email]);
return stmt->fetch(\PDO::FETCH_ASSOC);
?>
JWT-сервис для аутентификации
<?php
namespace App\Services;
class JwtService {
private string secret;
private int expire;
public function __construct() {
this->secret = _ENV['JWT_SECRET'] ?? 'your-secret-key';
this->expire = time() + 3600; // 1 час
public function generate(array payload): string {
header = base64_encode(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
payload[
exp
]=this->expire;
64
payload=base64
ncode(json
ncode(payload));
256
signature=hash
mac(
sha256
,header . '.' .
payload,this->secret, true);
64
signature=base64
ncode(signature);
return
header.
.payload . '.' . signature;
public function validate(string token): array|false {
header,payload,
signature]=explode(
,token);
expectedSignature = base64_encode(
hash_hmac('sha256', header . '.' .
payload,this->secret, true)
);
if (
signature!==expectedSignature) {
return false;
64
data=json
ecode(base64
ecode(payload), true);
if (data['exp'] < time()) {
return false;
return data;
?>
Middleware для проверки JWT
jwtService = new JwtService();
public function validate(string token): void {
if (empty(token)) {
http_response_code(401);
echo json_encode(['error' => 'Authorization token required']);
exit;
token=str
eplace(
Bearer
′′
,token);
payload=this->jwtService->validate(token);
if (!payload) {
http_response_code(401);
echo json_encode(['error' => 'Invalid or expired token']);
exit;
?>
Конфигурация базы данных
\PDO::ERRMODE_EXCEPTION]
);
} catch (\PDOException e) {
die('Database connection failed: ' . e->getMessage());
return self::instance;
?>
Тестирование API
Примеры запросов через cURL:
# Регистрация пользователя
curl -X POST http://localhost/rest-api/public/api/auth/register \n -H 'Content-Type: application/json' \n -d '{"name":"Иван","email":"ivan@example.com","password":"secret123"}'
# Авторизация (получение JWT)
curl -X POST http://localhost/rest-api/public/api/auth/login \n -H 'Content-Type: application/json' \n -d '{"email":"ivan@example.com","password":"secret123"}'
# Получение списка пользователей (с токеном)
curl -X GET http://localhost/rest-api/public/api/users \n -H 'Authorization: Bearer YOUR_JWT_TOKEN'
Итог
Мы создали полноценный REST API на чистом PHP с маршрутизацией, JWT-аутентификацией и работой с БД через PDO. Такой подход помогает понять основы, которые затем используются в любом фреймворке.