Créer une API REST
Configuration
Connexion à la base de données
Éditez le fichier config/config.php
:
<?php
return [
'development_environment' => false,
'default_locale' => 'en_US',
'default_timezone' => 'Europe/Paris',
'base_url' => 'http://example.com',
'database' => [
'type' => 'pgsql',
'server' => 'localhost',
'username' => 'postgres',
'password' => 'password123',
'name' => 'mydb',
'schema' => 'bluebird'
],
'filters' => [
'RoutingFilter'
]
];
?>
Éditez le fichier config/dependencies.php
et ajoutez les lignes
suivantes :
IoC::register( 'settings', function() {
return new Configuration( new JSONFileConfigurationHandler( CONFIG_DIR . 'settings.json' ) );
}, true );
Créez un fichier nommé settings.json
sous config
avec le contenu suivant :
{
"users.items-per-page": 20
}
Modèle de données
Créez la table suivante dans la base de données :
CREATE TABLE `user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`encrypted_password` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`user_id`)
);
Le modèle
Dans application/models
créez un fichier nommé
user.class.php
contenant :
<?php
namespace models;
use \ActiveRecord;
class User extends ActiveRecord {
protected function validate() {
$this->validateNotEmpty( 'username', 'Username cannot be empty.' );
$this->validateMaxLength( 'username', 30, 'Username is too long (maximum is 30 characters).' );
}
protected function validateOnInsert() {
$this->validateNotEmpty( 'password', 'Password cannot be empty.' );
}
protected function validateOnUpdate() {
if ( $this->isAttributeChanged( 'username' ) ) {
$this->validateUnique( 'username', 'Username already taken.' );
}
if ( $this->isAttributeChanged( 'email' ) ) {
$this->validateUnique( 'email', 'Email already in use.' );
}
}
protected function beforeSave() {
if ( !empty( $this->password ) ) {
$this->password = trim( $this->password );
$this->encrypted_password = password_hash( $this->password, PASSWORD_DEFAULT );
unset( $this->password );
}
$this->email = trim( $this->email );
$this->email = strtolower( $this->email );
}
}
Voir Le modèle : ActiveRecord pour plus de détails sur l'utilisation d'ActiveRecord pour définir les classes de modèles.
Les routes
Dans config/routes.json
, définissez les routes suivantes :
[
["GET", "api/v1/users", "controllers\\UserController@list"],
["GET", "api/v1/users/{id:\\d+}", "controllers\\UserController@show"],
["POST", "api/v1/users/", "controllers\\UserController@add"],
["PATCH", "api/v1/users/{id:\\d+}", "controllers\\UserController@update"],
["DELETE", "api/v1/users/{id:\\d+}", "controllers\\UserController@delete"]
]
Le contrôleur
Lister les utilisateurs
Dans application/controllers
, créez un fichier nommé
usercontroller.class.php
contenant :
<?php
namespace controllers;
use \ActionController;
use \IoC;
use \Paginator;
use \JSONHandler;
use models\User;
class UserController extends ActionController {
public function doList() {
$currentPage = $this->request->getParameters()->getInt( 'page', 1 );
if ( !\Validator::validateInteger( $currentPage ) ) {
$this->forward( 'controllers\\ErrorController', '400' );
}
$settings = IoC::resolve( 'settings' );
$totalItems = User::count();
$paginator = new Paginator( $settings['users.items-per-page'], $totalItems, $currentPage );
$this->response->addHeader( 'Content-type', 'application/json' );
$this->renderText( JSONHandler::encode( User::findMany( ['user_id', 'username', 'email'], ['LIMIT' => [$paginator->getOffset(), $paginator->getLimit()]] ) ) );
}
}
La classe UserController
étend la classe de base pour les
contrôleurs d'action ActionController
.
L'action doList
retourne la liste des utilisateurs.
La classe Paginator
permet de paginer les résultats.
Le nombre d'enregistrements par page est paramétrable dans le fichier de
paramétrage applicatif config/settings.json
.
La page courante est fournie en paramètre query string.
Le paramètre LIMIT
dans la requête permet de spécifier la
clause LIMIT
.
L'appel à addHeader
sur l'objet Response
permet de
définir le type MIME de la réponse : application/json
.
Récupérer un utilisateur
L'action doShow
retourne l'utilisateur correspond au
user_id
spécifié :
public function doShow() {
$user = User::findOne( ['user_id', 'username', 'email'], ['user_id' => $this->request->getAttribute( 'id' )] );
if ( empty( $user ) ) {
$this->forward( 'controllers\\ErrorController', '404' );
}
$this->response->addHeader( 'Content-type', 'application/json' );
$this->renderText( JSONHandler::encode( $user ) );
}
Si l'utilisateur n'existe pas, une erreur 404 sera retournée.
Créer un utilisateur
L'action doAdd()
crée un utilisateur.
public function doAdd() {
$json = file_get_contents( 'php://input' );
$data = JSONHandler::decode( $json, true );
$user = new User( $data );
if ( !$user->save() ) {
$this->response->setStatus( 400 );
$this->response->addHeader( 'Content-type', 'application/json' );
$this->renderText( JSONHandler::encode( $user->getErrors() ) );
} else {
$this->renderText( 'OK' );
}
}
Modifier un utilisateur
L'action doUpdate()
permet de modifier un utilisateur.
public function doUpdate() {
$json = file_get_contents( 'php://input' );
$data = JSONHandler::decode( $json, true );
$user = User::findOne( $this->request->getAttribute( 'id' ) );
if ( empty( $user ) ) {
$this->forward( 'controllers\\ErrorController', '404' );
}
if ( isset( $data['username'] ) ) {
$user->username = $data['username'];
}
if ( isset( $data['password'] ) ) {
$user->password = $data['password'];
}
if ( isset( $data['email'] ) ) {
$user->email = $data['email'];
}
if ( !$user->save() ) {
$this->response->setStatus( 400 );
$this->renderText( JSONHandler::encode( $user->getErrors() ) );
} else {
$this->renderText( 'OK' );
}
}
Si l'utilisateur n'existe pas, une erreur 404 sera retournée.
Supprimer un utilisateur
L'action doDelete()
supprime un utilisateur.
public function doDelete() {
$user = User::findOne( $this->request->getAttribute( 'id' ) );
if ( empty( $user ) ) {
$this->forward( 'controllers\\ErrorController', '404' );
}
$user->delete();
$this->renderText( '' );
}
Si l'utilisateur n'existe pas, une erreur 404 sera retournée.
Gestion des erreurs : ErrorController
Ouvrez le fichier
application/controllers/errorcontroller.class.php
et ajoutez la
ligne suivante :
use \JSONHandler;
Modifiez la méthode do404()
comme suit :
public function do404() {
$this->response->setStatus( 404 );
$this->renderText( JSONHandler::encode( ['error' => ['status' => 404, 'message' => 'Resource not found.'] ] ) );
}
Modifiez la méthode do500()
comme suit :
public function do500() {
$this->response->setStatus( 500 );
$this->renderText( JSONHandler::encode( ['error' => ['status' => 500, 'message' => 'Unexpected error.'] ] ) );
}
Modifiez la méthode do400()
comme suit :
public function do400() {
$this->response->setStatus( 400 );
$this->renderText( JSONHandler::encode( ['error' => ['status' => 400, 'message' => 'Bad Request.'] ] ) );
}
Test de l'API
Nous utilisons cURL pour tester l'API.
Lister les utilisateurs
curl http://[servername]/api/v1/users
Récupérer un utilisateur
curl http://[servername]/api/v1/users/1
Créer un utilisateur
curl -X POST -H "Content-Type: application/json" -d '{"username": "jon", "password": "secret123@", "email": "jon@example.com"}' http://[servername]/api/v1/users/
Modifier un utilisateur
curl -X PATCH -H "Content-Type: application/json" -d '{"email": "jon2@example.com"}' http://[servername]/api/v1/users/1
Supprimer un utilisateur
curl -X DELETE http://[servername]/api/v1/users/2