Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - ffremont/HugeRest: Framework PHP pour créer simplement, rapidement et efficacement une webapp REST · GitHub
Skip to content

Latest commit

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

HugeRest

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST Exemple : https://github.com/ffremont/HugeRest-samples

##Installation Installer avec composer

 {
"require": {
"huge/rest": "...",
"doctrine/cache" : "v1.3.0"
}
}

.htaccess :

<IfModulemod_rewrite.c>
RewriteEngineOnRewriteRule^$index.php [QSA,L]
RewriteCond%{REQUEST_FILENAME}!-fRewriteCond%{REQUEST_FILENAME}!-dRewriteRule^(.*)$index.php [QSA,L]
</IfModule>
$loader = require(__DIR__.'/../../../vendor/autoload.php');
// nécessaire charger les annotations
\Huge\IoC\Container\SuperIoC::registerLoader(array($loader, 'loadClass'));

Fonctionnalités

  • Définition des ressources et des chemins via : @Resource / @Path("CHEMIN")
  • Gestion des méthodes HTTP : @Get, @Put, @Post, @Delete
  • Personnalisation des types mimes : @Consumes({"...", "..."})
    • Permet de définir les accepts (GET, Delete) ou le content-type (POST, PUT)
  • Personnalisation du content type de la réponse : @Produces({"...", "..."})
  • Personnalisation des contenus
    • interprétation du contenu de la requête : implémentation de Huge\Rest\Process\IBodyReader
    • interprétation du contenu de la réponse : implémentation de Huge\Rest\Process\IBodyWriter
    • validation des contenus l'interface : Huge\Rest\Data\IValidator
  • Gestion des erreurs extra-souple : implémentation de Huge\Rest\Process\IExceptionMapper
  • Gestion de filtres sur les requêtes : implémentation de Huge\Rest\Process\IFilter
  • Gestion d'intercepteurs sur les requêtes : implémentation de Huge\Rest\Process\IInterceptor
  • Cache : basé sur doctrine cache
  • Annotations basé sur doctrine annotations

Configuration

$ioc = new \Huge\Rest\WebAppIoC('1.1', array(
'maxBodySize' => 1024// taille max en octet des body (par défaut ini_get('post_max_size')). Un flux Json en PUT / POST ne pourra pas faire + d'1Ko dans cet exemple
));

Création d'une ressource

  • Une ressource REST se matérialise par une classe PHP annotée. C'est un composant au sens Huge\IoC.

  • Utilisation des annotations :

    • @Resource obligatoire
    • @Path facultatif
    • @Consumes facultatif
      • Si POST, PUT cela correspond au contentType de la requête
      • Sinon, cela correspond à l'entête accept de la requête
    • @Produces facultatif
      • Définition du typeMime de sortie
      • Si POST, PUT cela correspond à l'entête accept de la requête
      • Sinon, cela correspond au contentType de la réponse
  • Les @Path sont des regexp

    • les chaînes trouvées sont ajoutées en paramètres de la fonction
  • Liste des tokens :

    • ':mString' => '([a-zA-Z]+)'
    • ':mNumber' => '([0-9]+)'
    • ':mAlpha' => '([a-zA-Z0-9-_]+)'
    • ':oString' => '([a-zA-Z]*)'
    • ':oNumber' => '([0-9]*)'
    • ':oAlpha' => '([a-zA-Z0-9-_]*)'
/** * EXEMPLE * Ressource "Person" qui a pour chemin "person". Notre ressource produit en retour une structure JSON en v1 par défaut.  * Chaque opération de la classe prend par défaut du "application/vnd.person.v1+json" / "application/json". * Si on surcharge sur la fonction @Consumes / @Produces alors la configuration de la fonction primera. *  * @Component * @Resource * @Path("person") *  * @Consumes({"application/vnd.person.v1+json", "application/json"}) * @Produces({"application/vnd.person.v1+json"}) */class Person {
/** * @Autowired("Huge\Rest\Http\HttpRequest") * @var \Huge\Rest\Http\HttpRequest */private$request;
/** * @Autowired("Huge\IoC\Factory\ILogFactory") * @var \Huge\IoC\Factory\ILogFactory */private$loggerFactory;
publicfunction__construct() {}
/** * @Get * @Consumes({"text/plain"}) * @Produces({"text/plain"}) */publicfunctionping() { return HttpResponse::ok();
}
/** * @Get * @Path(":mNumber") */publicfunctionget($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Delete * @Path(":mNumber") */publicfunctiondelete($id = '') {
$person = new \stdClass();
$person->id = $id;
return HttpResponse::ok()->entity($person);
}
/** * @Put * @Path(":mNumber") */publicfunctionput($id = '') {
// @Consumes retenu est celui de la classe (du json)$requestBody = (object)$this->request->getEntity();
$requestBody->id = $id;
return HttpResponse::ok()->entity($requestBody);
}
/** * Accepte le content-type application/json * @Post */publicfunctionpost() {
$person = new \stdClass();
$person->id = uniqid();
return HttpResponse::ok()->code(201)->entity($person);
}
/** * @Get * @Path("search/?:oNumber/?:oNumber") */publicfunctionsearch($numberA = '', $numberB = '') {
$query = $this->request->getParam('query');
$list = array();
for ($i = 0; $i < 5; $i++) {
$person = new \stdClass();
$person->id = uniqid();
$person->query = $query;
$person->a = $numberA;
$person->b = $numberB;
$list[] = $person;
}
return HttpResponse::ok()->entity($list);
}
publicfunctiongetRequest() {
return$this->request;
}
publicfunctionsetRequest($request) {
$this->request = $request;
}
publicfunctiongetLoggerFactory() {
return$this->loggerFactory;
}
publicfunctionsetLoggerFactory(\Huge\IoC\Factory\ILogFactory$loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
}

Gérer un contenu de requête

  • Pour gérer les types mime des requêtes HTTP vous avez la possibilité d'implémenter vos propres "IBodyReader"
  • Interface à implémenter : Huge\Rest\Process\IBodyReader
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyReaders(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Readers\JsonReader'
));
  • Liste et configuration des readers disponibles (l'instance HttpResquet = $r)
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Readers\FormReader', => $r->getBody() : $_REQUEST
    • 'application/json' => 'Huge\Rest\Process\Readers\JsonReader', => $r->getBody() : json_decode
    • 'text/plain' => 'Huge\Rest\Process\Readers\TextReader', => $r-getBody() => au body de la request
    • 'multipart/form-data' => 'Huge\Rest\Process\Readers\UploadReader', => $r->getBody() : instance Huge\Rest\Http\HttpFiles
    • 'multipart/octet-stream' => 'Huge\Rest\Process\Readers\UploadReader', // idem
    • 'application/octet-stream' => 'Huge\Rest\Process\Readers\BinaryReader' => $r->getBody() : instance Huge\Rest\Data\TempFile

Gérer un contenu de réponse

  • Une fonction d'une ressource retourne une instance de l'objet Huge\Rest\Http\HttpResponse. Cette dernière peut avoir l'attribut "entity" de valorisé qui sera à convertir en fonction du contentType souhaité de la réponse HTTP.
  • Interface à implémenter : Huge\Rest\Process\IBodyWriter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addBodyWriters(array(
'application/vnd.github.v1+json' => 'Huge\Rest\Process\Writers\JsonWriter'
));
  • Liste et configurations des writers disponibles
    • 'application/x-www-form-urlencoded' => 'Huge\Rest\Process\Writers\FormWriter', => encode $entity avec urlencode
    • 'application/json' => 'Huge\Rest\Process\Writers\JsonWriter', => encode $entity avec json_encode
    • 'text/plain' => 'Huge\Rest\Process\Writers\TextWriter' => caste en string

Filtrer les requêtes et réponses

  • Les filtres permettent d'exercer des contrôles avant les traitements REST. Un filtre est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IRequestFilter
  • Interface à implémenter : Huge\Rest\Process\IResponseFilter
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Security\Authorization',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\Security\AuthorizationBis',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
),array(
'class' => 'MyWebApi\PowerByFilter',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));
$ioc->addRequestFiltersMapping(array(
'MyWebApi\Security\Authorization' => '.*', /* applique le filtre sur toutes les ressources */'MyWebApi\Security\AuthorizationBis'/* on ne tient pas compte des paths */
));
$ioc->addResponseFiltersMapping(array(
'MyWebApi\PowerByFilter' => '.*'
));

Intercepter les traitements REST

  • Pour différentes raisons vous aurez besoin de connaître le début et la fin des traitements de votre API. Un intercepteur est un composant au sens Huge\IoC.
  • Interface à implémenter : Huge\Rest\Process\IInterceptor
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Interceptors\Custom',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
)
));

Validateurs sur les modèles

  • Basé sur fuelphp validation https://github.com/fuelphp/validation

  • Il est possible de valider les données qui sont passées dans le body de la requête.

  • Interface que le modèle doit implémenter : Huge\Rest\Data\IValidator

    // dans votre classe ressource/*** @Autowired("Huge\Rest\Http\BodyReader")*/private$bodyReader;
    // dans votre fonction$this->bodyReader->validateEntity('...nom_de_la_classe_modele...');
    // ou$this->bodyReader->validateEntityList('...nom_de_la_classe_modele...'); // si le contenu est une liste
    • Lancement de l'exception : Huge\Rest\Exceptions\ValidationException
  • Personnalisation du validateur fuelPhp \Huge\Rest\Data\IFuelValidatorFactory

    $webAppIoC->setFuelValidatorFactory($votre_factory)

Personnaliser les erreurs

  • Votre webapp va pouvoir emettre des exceptions qu'il va falloir convertir en réponse HTTP. Pour réaliser cela, il va être nécessaire d'enregistrer des couples selon le format : "Nom de l'exception" => "Nom de la classe qui implémente".
  • Interface à implémenter : Huge\Rest\Process\IExceptionMapper
  • Il est possible de définir un mapper d'exceptions par défaut "Exception" => "MonMapper"
$ioc = new \Huge\Rest\WebAppIoC('1.0');
$ioc->addDefinitions(array(
array(
'class' => 'MyWebApi\Exceptions\LogicMapper',
'factory' => \Huge\IoC\Factory\SimpleFactory::getInstance()
) // définition des autres composants qui implémentes IExceptionMapper...
));
$ioc->addExceptionsMapping(array(
'LogicException' => 'MyWebApi\Exceptions\LogicMapper',
'Huge\Rest\Exceptions\NotFoundResourceException' => null, // désactivation du mapper'Exception' => 'MyWebApi\Exceptions\DefaultExceptionMapper'
));
  • Liste des mappers :
    • 'Huge\Rest\Exceptions\NotFoundResourceException' => 'Huge\Rest\Exceptions\Mappers\NotFoundResourceExceptionMapper',
    • 'Huge\Rest\Exceptions\InvalidResponseException' => 'Huge\Rest\Exceptions\Mappers\InvalidResponseExceptionMapper',
    • 'Huge\Rest\Exceptions\ValidationException' => 'Huge\Rest\Exceptions\Mappers\ValidationExceptionMapper',
    • 'Huge\Rest\Exceptions\WebApplicationException' => 'Huge\Rest\Exceptions\Mappers\WebApplicationExceptionMapper',
    • 'Huge\Rest\Exceptions\SizeLimitExceededException' => 'Huge\Rest\Exceptions\Mappers\SizeLimitExceededExceptionMapper',
    • 'Exception' => 'Huge\Rest\Exceptions\Mappers\DefaultExceptionMapper'

Logger

  • Implémenter la factory : Huge\IoC\Factory\ILogFactory
  • Ajouter le composant dans votre conteneur de plus haut niveau
    • Dans le cas où vous avez * conteneurs et que chacun dispose de son implémentation. L'injection (@Autowired de ILogFactory) ne marchera pas car * implémentations seront détectées.
    • Généralement, le conteneur WebApp contient l'implémentation et les classes des tests
  • Logger factory (composant) vide : Huge\Rest\Log\NullLoggerFactory

Ordonnancement

  • Analyse de la requête HTTP
    • à partir du composant Huge\Rest\Http\HttpRequest
    • détermination d'une route : Huge\Rest\Routing\Route (composant)
    • si aucune route n'existe, lancement de Huge\Rest\Exceptions\NotFoundResourceException
  • Analyse du contenu de la requête (POST ou PUT)
    • utilisation des IBodyReader
  • Exécution des Huge\Rest\Process\IRequestFilter
  • Exécution de la fonction start des intercepteurs Huge\Rest\Process\IInterceptor
  • EXECUTION DU TRAITEMENT LIE A LA RESSOURCE
  • Détermination du contentType à appliquer dans la réponse HTTP
    • utilisation des IBodyWriter
  • Exécution des Huge\Rest\Process\IResponseFilter
  • Exécution de la fonction end des intercepteurs Huge\Rest\Process\IInterceptor
  • Construction de la réponse : Huge\Rest\Http\HttpResponse (fonction build)

Limitations

  • La gestion des erreurs ne permet pas d'exploiter l'héritage des exceptions
  • Logger basé sur l'interface Psr\Log : https://packagist.org/packages/psr/log
  • Basé sur Huge\IoC
  • Validateur basé sur fuel validation

Tests

  • Tests unitaires : phpunit -c src/test/resources/phpunit.xml --testsuite TU
  • Tests d'intégration avec apache2 sur src/test/webapp : phpunit -c src/test/resources/phpunit.xml --testsuite IT

About

Framework PHP pour créer simplement, rapidement et efficacement une webapp REST

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages