2017 © Pedro PelĂĄez
 

library rest

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

image

huge/rest

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

  • Wednesday, September 3, 2014
  • by floorent
  • Repository
  • 1 Watchers
  • 4 Stars
  • 109 Installations
  • PHP
  • 1 Dependents
  • 0 Suggesters
  • 2 Forks
  • 0 Open issues
  • 7 Versions
  • 0 % Grown

The README.md

HugeRest

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

Installation

Installer avec composer ``` json { "require": { "huge/rest": "...", "doctrine/cache" : "v1.3.0" } }, (*2)


.htaccess : ```apache <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^$ index.php [QSA,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ 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 :, (*3)

    • @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, (*4)

    • 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;

    public function __construct() {}

    /**
     * @Get
     * @Consumes({"text/plain"})
     * @Produces({"text/plain"})
     */
    public function ping() {        
        return HttpResponse::ok();
    }

    /**
     * @Get
     * @Path(":mNumber")
     */
    public function get($id = '') {
        $person = new \stdClass();
        $person->id = $id;

        return HttpResponse::ok()->entity($person);
    }

    /**
     * @Delete
     * @Path(":mNumber")
     */
    public function delete($id = '') {
        $person = new \stdClass();
        $person->id = $id;

        return HttpResponse::ok()->entity($person);
    }

     /**
     * @Put
     * @Path(":mNumber")
     */
    public function put($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
     */
    public function post() {
        $person = new \stdClass();
        $person->id = uniqid();

        return HttpResponse::ok()->code(201)->entity($person);
    }

    /**
     * @Get
     * @Path("search/?:oNumber/?:oNumber")
     */
    public function search($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);
    }

    public function getRequest() {
        return $this->request;
    }

    public function setRequest($request) {
        $this->request = $request;
    }

    public function getLoggerFactory() {
        return $this->loggerFactory;
    }

    public function setLoggerFactory(\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, (*5)

    // 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 php $webAppIoC->setFuelValidatorFactory($votre_factory), (*6)

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

The Versions

03/09 2014

dev-master

9999999-dev

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

03/09 2014

v1.0.3

1.0.3.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

23/08 2014

v1.0.2

1.0.2.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

18/08 2014

v1.0.1

1.0.1.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

18/08 2014

v1.0.0

1.0.0.0

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

03/08 2014

v1.0.0-BETA2

1.0.0.0-beta2

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

  Sources   Download

MIT

The Requires

 

The Development Requires

by Florent FREMONT

api rest ioc webapp bean

29/07 2014

v1.0.0-BETA

1.0.0.0-beta

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

  Sources   Download

MIT

The Requires

 

by Florent FREMONT

api rest ioc webapp bean