Créer une API REST avec PHP est une compétence fondamentale pour tout développeur backend. Dans ce guide, vous allez apprendre à concevoir, coder et sécuriser une API REST PHP de zéro, sans framework lourd, avec juste PHP natif et de bonnes pratiques.
Qu'est-ce qu'une API REST ?
Une API REST (Representational State Transfer) est une interface qui permet à deux applications de communiquer via HTTP. Elle repose sur des conventions simples :
- GET : récupérer des données
- POST : créer une ressource
- PUT / PATCH : modifier une ressource
- DELETE : supprimer une ressource
Prérequis
Avant de commencer, assurez-vous d'avoir :
- PHP 8.1+ installé
- Un serveur local (Apache, Nginx, ou le serveur intégré de PHP)
- Un outil pour tester les requêtes HTTP : Postman ou curl
Structure du projet
Voici l'arborescence minimale pour une API REST PHP :
api/
├── index.php ← Point d'entrée
├── router.php ← Routeur simple
├── controllers/
│ └── ArticleController.php
├── models/
│ └── Article.php
└── config/
└── database.php
Étape 1 : Le point d'entrée (index.php)
Toutes les requêtes doivent passer par index.php. Configurez votre .htaccess pour réécrire les URLs :
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
Dans index.php, définissez les en-têtes CORS et le type de contenu :
<?php
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
require_once 'router.php';
Étape 2 : Le routeur
Un routeur simple qui mappe les URLs vers des contrôleurs :
<?php
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = trim($uri, '/');
$segments = explode('/', $uri);
// Route: GET /api/articles
if ($method === 'GET' && $segments[0] === 'api' && $segments[1] === 'articles') {
require_once 'controllers/ArticleController.php';
$controller = new ArticleController();
if (isset($segments[2]) && is_numeric($segments[2])) {
$controller->show((int)$segments[2]);
} else {
$controller->index();
}
} elseif ($method === 'POST' && $segments[0] === 'api' && $segments[1] === 'articles') {
require_once 'controllers/ArticleController.php';
$controller = new ArticleController();
$controller->store();
} else {
http_response_code(404);
echo json_encode(['error' => 'Route non trouvée']);
}
Étape 3 : Le contrôleur
<?php
class ArticleController {
private PDO $db;
public function __construct() {
$this->db = new PDO(
'mysql:host=localhost;dbname=blog;charset=utf8',
'root', '',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
}
public function index(): void {
$stmt = $this->db->query('SELECT * FROM articles ORDER BY created_at DESC');
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode([
'success' => true,
'data' => $articles,
'count' => count($articles)
]);
}
public function show(int $id): void {
$stmt = $this->db->prepare('SELECT * FROM articles WHERE id = ?');
$stmt->execute([$id]);
$article = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$article) {
http_response_code(404);
echo json_encode(['error' => 'Article non trouvé']);
return;
}
echo json_encode(['success' => true, 'data' => $article]);
}
public function store(): void {
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['title']) || empty($data['content'])) {
http_response_code(422);
echo json_encode(['error' => 'Les champs title et content sont requis']);
return;
}
$stmt = $this->db->prepare(
'INSERT INTO articles (title, content, created_at) VALUES (?, ?, NOW())'
);
$stmt->execute([$data['title'], $data['content']]);
http_response_code(201);
echo json_encode([
'success' => true,
'id' => $this->db->lastInsertId()
]);
}
}
Étape 4 : Authentification par token JWT
Pour sécuriser votre API REST PHP, utilisez des tokens JWT ou une clé API simple :
function verifyApiKey(): void {
$headers = getallheaders();
$apiKey = $headers['X-Api-Key'] ?? '';
if ($apiKey !== getenv('API_SECRET_KEY')) {
http_response_code(401);
echo json_encode(['error' => 'Non autorisé']);
exit();
}
}
Appelez verifyApiKey() au début de chaque route protégée.
Étape 5 : Gestion des erreurs
Une bonne API REST PHP retourne toujours des codes HTTP appropriés :
| Code | Signification |
|---|---|
| 200 | Succès |
| 201 | Ressource créée |
| 400 | Requête invalide |
| 401 | Non authentifié |
| 403 | Interdit |
| 404 | Non trouvé |
| 422 | Données invalides |
| 500 | Erreur serveur |
Tester votre API REST PHP
Avec curl, testez vos endpoints facilement :
# GET tous les articles
curl -X GET http://localhost/api/articles
# POST créer un article
curl -X POST http://localhost/api/articles \
-H "Content-Type: application/json" \
-d '{"title": "Mon article", "content": "Contenu..."}'
Bonnes pratiques à retenir
- Versionnez votre API : préfixez vos routes avec
/api/v1/ - Paginez les résultats : n'envoyez jamais 10 000 lignes d'un coup
- Validez toujours les entrées : ne faites jamais confiance aux données client
- Utilisez HTTPS en production
- Documentez votre API avec des outils comme Swagger/OpenAPI
Aller plus loin
Une fois cette base maîtrisée, explorez des frameworks PHP comme Laravel ou Slim qui offrent un routeur, une ORM et une structure prête à l'emploi pour créer des API REST PHP robustes rapidement.
Pour aller plus loin : Documentation PHP officielle sur les requêtes HTTP