REST API на чистом PHP: создание и документация

JavaScript · 19.07.2026 · 4 мин чтения

Создание REST API на чистом PHP — отличный способ понять основы. Разбираем маршрутизацию, контроллеры, работу с БД и аутентификацию.

Архитектура REST API на PHP с маршрутизацией и контроллерами

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. Такой подход помогает понять основы, которые затем используются в любом фреймворке.

JavaScript Frontend Linting
← Ко всем статьям

Читайте также