La validation des contrats
d’interfaces au format OpenAPI
Meetup - 16 Mai 2017
Marseille PHP User Group - AFUP
Nicolas Macherey – Fondateur WakeOnWeb
OpenAPI/Swagger: Qu’est-ce que c’est ?
• Un format simple, compréhensible et collaboratif
• Complet, très répandu
• YAML ou JSON
• Structuré et respectant l’HTTP
• Facile à intégrer au SCM (Git ou autre)
• Permet de sortir une doc simple et compréhensible
• Des outils dédiés
• Swagger Editor: Editeur web avancé avec système de validation
• Swagger UI: Générateur de documentation à partir de la spec
• Swagger CodeGen: Générateur de code client/serveur
Swagger UI permet aussi de tester les APIs manuellement en
faisant des appels depuis l’interface exposant la documentation.
http://swagger.io/
swagger: '2.0’
info:
version: "1.0.0"
title: Basic Auth Example
description: |
An example for how to use Basic Auth with Swagger.
**User Name and Password**
* User Name: `user`
* Password: `pass`
host: basic-auth-server.herokuapp.com
schemes:
- http
- https
securityDefinitions:
basicAuth:
type: basic
description: HTTP Basic Authentication….
paths:
/:
get:
security:
- basicAuth: []
responses:
200:
description: Will send `Authenticated`…
Méthodologies: Contract First/Last mais pourquoi ?
Contract Last
Les spécifications d’API sont extraites du code comme un
constat de ce qui a été fait…
• Agile/Plus rapide
• Moins collaboratif Très difficile de paralléliser le travail
• Correspond toujours à la réalité de l’API
Contract First
Les spécifications sont le cœur central du développement
elles sont faites au moment des phases de spécifications
• Facilite le travail parallèle (Gain de productivité)
• Moins agile, nécessite la mise en place de
communications dédiées
• Peut contenir des différences à l’implémentation
(Recette)
• Permet la génération automatique de code serveur
Les enjeux architecturaux récents…
• Propriétés
• Chaque service peut être (et est) conçu, développé, testé et déployé
indépendamment.
• De ce fait, il peut évoluer a son rythme.
• Bénéficie d’une forte cohésion interne à l’application.
• Est parfaitement adapté aux technologies de type docker, permettant
de déployer chaque service dans un conteneur dédié.
• Avantages
• Réduction du Time To Market, notamment en parallélisant les
développements
• Flexibilité technologique et indépendance pour chaque service
• Extensibilité / Evolutivité largement facilité
• Résilience augmentée
• Réduction des coûts de maintenance et d’évolution
• Réduction des risques
Mais il y a tout de même des règles à respecter pour que cela se
passe bien…
API GATEWAY
L’importance de valider que les nouvelles évolutions
respectent les contrats d’interface dans une suite distribuée
(entrée/sortie)
Intégration aux tests automatisés
Intégration continue
Non-Régression
Objectif n°1: Mieux gérer ses évolutions
Identifier les erreurs
Sécuriser ses API
Faciliter ses traitements métiers
Intégration aux frameworks
Intégration en production
Objectif n°2: Faciliter le traitement des requêtes HTTP
WakeOnWeb/swagger: Présentation
▪ Répondre à un besoin (d’abord perso...)
▪ L’existant n’était pas satisfaisant
▪ Faciliter nos phases d’intégrations front/back ou dans nos suites de services
▪ Une première ouverture vers l’OpenSource/Contribution communautaire
▪ Un composant utilisable au sein de tous les frameworks PHP (Silex, Laravel, Symfony…)
▪ Extensible et rapide
▪ Compatible avec différents validateurs de données JSON (JustinRainbow/Jval…)
WakeOnWeb/swagger: Fonctionnalités
▪ Ajout de validateurs personnalisés
▪ Compatibilité PSR-7 (MessageInterface)
▪ Compatibilité PSR-6 (Cache)
▪ Respect de la spécification OpenAPI au format Swagger 2.0 (3.0 à venir)
▪ Gestion des extensions vendor spécifiques
▪ Intégration PHPUnit/Behat
▪ Intégration Symfony
WakeOnWeb/swagger: Installation
> composer require wakeonweb/swagger
> composer require justinrainbow/json-schema
Le composant intègre 1 bridge et permet d’en intégrer
d’autres
// File system for cache storage

$filesystem = new Filesystem(new Local('path/to/wakeonweb/swagger'));

$factory = new SwaggerFactory(new FilesystemCachePool($filesystem));



// Add loader Yaml and JSON supported

$factory->addLoader(new YamlLoader());



// Parse file and store to cache directory and/or read the file content

$swagger = $factory->buildFrom('path/to/swagger.yml');

$this->swaggerValidator = new SwaggerValidator($swagger);



// Register the appropriate JSON Schema Validator for Content validation

$this->swaggerValidator->registerContentValidator(new JustinRainbowJsonSchemaValidator());



// Converts the response to a PRS-7 compliant format.

$response = (new DiactorosFactory())->createResponse($response);



// Validate the response for the given path/method/status

$this->swaggerValidator->validateResponseFor(
$response,

PathItem::METHOD_GET, '/api/users/{id}/orders', 200
);
WakeOnWeb/swagger: Utilisation
WakeOnWeb/swagger: Exemple d’intégration a Behat
class OpenApiValidationContext implements Context, SnippetAcceptingContext

{

use KernelDictionary;

private $swaggerValidator;



/**

* @BeforeScenario

*/

public function loadSwaggerValidator()

{

$kernel = $this->getContainer()->get('kernel'); 

$filesystem = new Filesystem(new Local($kernel->getCacheDir() . '/wakeonweb/swagger'));

$factory = new SwaggerFactory(new FilesystemCachePool($filesystem));

$factory->addLoader(new YamlLoader());

$swagger = $factory->buildFrom($kernel->getRootDir() . '/../docs/api/swagger.yml');

$this->swaggerValidator = new SwaggerValidator($swagger);

$this->swaggerValidator->registerContentValidator(new JustinRainbowJsonSchemaValidator());

} 



/**

* @Then The response should validate :path open api specification with :method method and :statusCode status

*/

public function validateOpenApiSpecification($path, $method = PathItem::METHOD_GET, $statusCode = 200)

{

$this->swaggerValidator->validateResponseFor(
(new DiactorosFactory())->createResponse($this->response), $method, $path, $statusCode);

}
}
WakeOnWeb/swagger: Roadmap
▪ 7 Issues fonctionnelles planifiées pour faire évoluer le système (Juin 2016)
▪ Un travail pour permettre la validation des requêtes en production
▪ Analyse de performances
▪ Optimisation des traitements
▪ Evolutions des validateurs/JSON Schema
▪ Amélioration du processus de mise en cache
▪ Une intégration sous forme de bundle Symfony (Sept 2016) suivant 2 modes:
▪ Listener de requêtes
▪ Annotation
▪ Objectif: Profiter des fonctionnalités du Framework pour matcher les Routes avec les paths swagger
directement dans les Controllers, Intégration au système de gestion du cache de Symfony.
▪ Intégration avec Nelmio/ApiDocBunde (Compatible avec le format OpenAPI)
Merci
Si vous avez des questions…

AFUP Aix/Marseille - 16 mai 2017 - Open API

  • 1.
    La validation descontrats d’interfaces au format OpenAPI Meetup - 16 Mai 2017 Marseille PHP User Group - AFUP Nicolas Macherey – Fondateur WakeOnWeb
  • 2.
    OpenAPI/Swagger: Qu’est-ce quec’est ? • Un format simple, compréhensible et collaboratif • Complet, très répandu • YAML ou JSON • Structuré et respectant l’HTTP • Facile à intégrer au SCM (Git ou autre) • Permet de sortir une doc simple et compréhensible • Des outils dédiés • Swagger Editor: Editeur web avancé avec système de validation • Swagger UI: Générateur de documentation à partir de la spec • Swagger CodeGen: Générateur de code client/serveur Swagger UI permet aussi de tester les APIs manuellement en faisant des appels depuis l’interface exposant la documentation. http://swagger.io/ swagger: '2.0’ info: version: "1.0.0" title: Basic Auth Example description: | An example for how to use Basic Auth with Swagger. **User Name and Password** * User Name: `user` * Password: `pass` host: basic-auth-server.herokuapp.com schemes: - http - https securityDefinitions: basicAuth: type: basic description: HTTP Basic Authentication…. paths: /: get: security: - basicAuth: [] responses: 200: description: Will send `Authenticated`…
  • 3.
    Méthodologies: Contract First/Lastmais pourquoi ? Contract Last Les spécifications d’API sont extraites du code comme un constat de ce qui a été fait… • Agile/Plus rapide • Moins collaboratif Très difficile de paralléliser le travail • Correspond toujours à la réalité de l’API Contract First Les spécifications sont le cœur central du développement elles sont faites au moment des phases de spécifications • Facilite le travail parallèle (Gain de productivité) • Moins agile, nécessite la mise en place de communications dédiées • Peut contenir des différences à l’implémentation (Recette) • Permet la génération automatique de code serveur
  • 4.
    Les enjeux architecturauxrécents… • Propriétés • Chaque service peut être (et est) conçu, développé, testé et déployé indépendamment. • De ce fait, il peut évoluer a son rythme. • Bénéficie d’une forte cohésion interne à l’application. • Est parfaitement adapté aux technologies de type docker, permettant de déployer chaque service dans un conteneur dédié. • Avantages • Réduction du Time To Market, notamment en parallélisant les développements • Flexibilité technologique et indépendance pour chaque service • Extensibilité / Evolutivité largement facilité • Résilience augmentée • Réduction des coûts de maintenance et d’évolution • Réduction des risques Mais il y a tout de même des règles à respecter pour que cela se passe bien… API GATEWAY
  • 5.
    L’importance de validerque les nouvelles évolutions respectent les contrats d’interface dans une suite distribuée (entrée/sortie) Intégration aux tests automatisés Intégration continue Non-Régression Objectif n°1: Mieux gérer ses évolutions
  • 6.
    Identifier les erreurs Sécuriserses API Faciliter ses traitements métiers Intégration aux frameworks Intégration en production Objectif n°2: Faciliter le traitement des requêtes HTTP
  • 7.
    WakeOnWeb/swagger: Présentation ▪ Répondreà un besoin (d’abord perso...) ▪ L’existant n’était pas satisfaisant ▪ Faciliter nos phases d’intégrations front/back ou dans nos suites de services ▪ Une première ouverture vers l’OpenSource/Contribution communautaire ▪ Un composant utilisable au sein de tous les frameworks PHP (Silex, Laravel, Symfony…) ▪ Extensible et rapide ▪ Compatible avec différents validateurs de données JSON (JustinRainbow/Jval…)
  • 8.
    WakeOnWeb/swagger: Fonctionnalités ▪ Ajoutde validateurs personnalisés ▪ Compatibilité PSR-7 (MessageInterface) ▪ Compatibilité PSR-6 (Cache) ▪ Respect de la spécification OpenAPI au format Swagger 2.0 (3.0 à venir) ▪ Gestion des extensions vendor spécifiques ▪ Intégration PHPUnit/Behat ▪ Intégration Symfony
  • 9.
    WakeOnWeb/swagger: Installation > composerrequire wakeonweb/swagger > composer require justinrainbow/json-schema Le composant intègre 1 bridge et permet d’en intégrer d’autres
  • 10.
    // File systemfor cache storage
 $filesystem = new Filesystem(new Local('path/to/wakeonweb/swagger'));
 $factory = new SwaggerFactory(new FilesystemCachePool($filesystem));
 
 // Add loader Yaml and JSON supported
 $factory->addLoader(new YamlLoader());
 
 // Parse file and store to cache directory and/or read the file content
 $swagger = $factory->buildFrom('path/to/swagger.yml');
 $this->swaggerValidator = new SwaggerValidator($swagger);
 
 // Register the appropriate JSON Schema Validator for Content validation
 $this->swaggerValidator->registerContentValidator(new JustinRainbowJsonSchemaValidator());
 
 // Converts the response to a PRS-7 compliant format.
 $response = (new DiactorosFactory())->createResponse($response);
 
 // Validate the response for the given path/method/status
 $this->swaggerValidator->validateResponseFor( $response,
 PathItem::METHOD_GET, '/api/users/{id}/orders', 200 ); WakeOnWeb/swagger: Utilisation
  • 11.
    WakeOnWeb/swagger: Exemple d’intégrationa Behat class OpenApiValidationContext implements Context, SnippetAcceptingContext
 {
 use KernelDictionary;
 private $swaggerValidator;
 
 /**
 * @BeforeScenario
 */
 public function loadSwaggerValidator()
 {
 $kernel = $this->getContainer()->get('kernel'); 
 $filesystem = new Filesystem(new Local($kernel->getCacheDir() . '/wakeonweb/swagger'));
 $factory = new SwaggerFactory(new FilesystemCachePool($filesystem));
 $factory->addLoader(new YamlLoader());
 $swagger = $factory->buildFrom($kernel->getRootDir() . '/../docs/api/swagger.yml');
 $this->swaggerValidator = new SwaggerValidator($swagger);
 $this->swaggerValidator->registerContentValidator(new JustinRainbowJsonSchemaValidator());
 } 
 
 /**
 * @Then The response should validate :path open api specification with :method method and :statusCode status
 */
 public function validateOpenApiSpecification($path, $method = PathItem::METHOD_GET, $statusCode = 200)
 {
 $this->swaggerValidator->validateResponseFor( (new DiactorosFactory())->createResponse($this->response), $method, $path, $statusCode);
 } }
  • 12.
    WakeOnWeb/swagger: Roadmap ▪ 7Issues fonctionnelles planifiées pour faire évoluer le système (Juin 2016) ▪ Un travail pour permettre la validation des requêtes en production ▪ Analyse de performances ▪ Optimisation des traitements ▪ Evolutions des validateurs/JSON Schema ▪ Amélioration du processus de mise en cache ▪ Une intégration sous forme de bundle Symfony (Sept 2016) suivant 2 modes: ▪ Listener de requêtes ▪ Annotation ▪ Objectif: Profiter des fonctionnalités du Framework pour matcher les Routes avec les paths swagger directement dans les Controllers, Intégration au système de gestion du cache de Symfony. ▪ Intégration avec Nelmio/ApiDocBunde (Compatible avec le format OpenAPI)
  • 13.
    Merci Si vous avezdes questions…