DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Integration Zone»Agrégation des appels d’API REST à l’aide d’Apache Camel
    Integration Zone

    Agrégation des appels d’API REST à l’aide d’Apache Camel

    novembre 3, 2021
    Agrégation des appels d'API REST à l'aide d'Apache Camel
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Qu’est-ce qu’Apache Camel ?

    Comme décrit par le créateur lui-même, Claus Ibsen sur Apache Camel in Action, 2e édition :

    Au cœur du framework Camel se trouve un moteur de routage, ou plus précisément, un constructeur de moteur de routage. Il vous permet de définir vos propres règles de routage, de décider à partir de quelles sources accepter les messages et de déterminer comment traiter et envoyer ces messages vers d’autres destinations. Camel utilise un langage d’intégration qui vous permet de définir des règles de routage complexes, semblables à des processus métier. Comme le montre la figure 1.1, Camel forme la colle entre des systèmes disparates.

    L’un des principes fondamentaux de Camel est qu’il ne fait aucune hypothèse sur le type de données que vous devez traiter. C’est un point important, car il vous donne, en tant que développeur, la possibilité d’intégrer tout type de système, sans avoir besoin de convertir vos données dans un format canonique.

    Parmi les solutions d’intégration les plus diverses que nous pouvons construire avec Camel. Dans cet article, nous allons créer un agrégateur pour les appels d’API à l’aide de l’Enricher EIP. Le projet présenté dans cet article est disponible sur Github.

    Le scénario

    Pour montrer comment l’Enricher EIP peut être utilisé avec Camel, nous allons créer une application qui agrège les appels de deux API :

    Notre application Camel a deux points de terminaison :

    • [GET] /integration/authors – API d’auteurs de requêtes.

    • [GET] /integration/authors/{name} – Recherche auteur par nom (ex : `jr-tolkien`, `jk-rowling`) et enrichit la réponse avec tous les livres des auteurs.

    L’application Chameau

    Création de projet

    Pour créer le projet, nous pouvons accéder à https://start.spring.io/ et remplir les métadonnées du projet avec ces paramètres :

    Spring Boot: 2.3.1
    
    Group: br.com.camel.bookstore
    
    Artifact: camel-bookstore-aggregator
    
    Version: 1.0
    
    Name: camel-bookstore-aggregator
    
    Dependencies: 'Apache Camel'

    Ensuite, cliquez sur Générer pour créer le projet puis éditez le fichier pom.xml pour ajouter les dépendances que nous allons utiliser (undertow, rest, http).

    Le fichier pom.xml doit ressembler à ceci :

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
         <modelVersion>4.0.0</modelVersion>
         <parent>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>2.3.1.RELEASE</version>
              <relativePath/> <!-- lookup parent from repository -->
         </parent>
    
         <groupId>br.com.camel.bookstore</groupId>
         <artifactId>camel-bookstore-aggregator</artifactId>
         <version>1.0</version>
         <name>camel-bookstore-aggregator</name>
         <properties>
              <java.version>1.8</java.version>
              <camel.version>3.1.0</camel.version>
         </properties>
    
         <dependencies>
              <dependency>
                   <groupId>org.apache.camel.springboot</groupId>
                   <artifactId>camel-spring-boot-starter</artifactId>
                   <version>${camel.version}</version>
              </dependency>        
    
              <dependency>
                   <groupId>org.apache.camel.springboot</groupId>
                   <artifactId>camel-rest-starter</artifactId>
                   <version>${camel.version}</version>
              </dependency>
    
              <dependency>
                   <groupId>org.apache.camel</groupId>
                   <artifactId>camel-undertow</artifactId>
                   <version>${camel.version}</version>
              </dependency>
    
              <dependency>
                   <groupId>org.apache.camel</groupId>
                   <artifactId>camel-http</artifactId>
                   <version>${camel.version}</version>
              </dependency>
           
           ...
           
         </dependencies>
    </project>

    La route du repos

    Nous allons créer deux classes avec des itinéraires Camel. Le point de terminaison sera dans le RestRoute et les routes qui accèdent aux API et enrichissent le contenu seront dans la classe RestAggregatorRoute.

    @Component
    public class RestRoute extends RouteBuilder {
    
      @Override
      public void configure() throws Exception {
        //Define the server configurations like host address and port
        restConfiguration()
          .host("0.0.0.0").port(8080)
          .bindingMode(RestBindingMode.auto);
     
        //Mapping the REST endpoints
        rest("/integration")
          //Endpoint that queries all authors
          .get("/authors")
            .route().routeId("rest-all-authors")
            .to("direct:call-rest-all")
          .endRest()
         
          //Endpoint with the enrich EIP
          .get("/authors/{name}")
            .route().routeId("rest-author-by-name")
            .to("direct:call-rest-author")
          .endRest();
      }
    }

    Les points de terminaison /integration/authors et /integration/authors/{name} lorsqu’ils sont appelés appellent respectivement les routes direct:call-rest-all et direct:call-rest-author, ils sont définis dans l’autre classe.

    La voie de l’intégration

    Interroger l’API des auteurs

    Notre route utilise le composant http pour consommer l’API Authors et renvoyer tous les auteurs.

    from("direct:call-rest-all")
      .routeId("all-service")
      .removeHeaders("CamelHttp*")
      .setHeader(Exchange.HTTP_METHOD, constant("GET"))
    .to("http://{{authors.url}}/authors");

    Dans l’itinéraire, nous utilisons le removeHeaders("CamelHttp*") en nous assurant que notre appel API n’a que des en-têtes liés aux composants HTTP, et nous allons utiliser l’en-tête HTTP_METHOD avec GET comme valeur. La méthode .to reçoit « http://{{authors.url}}/authors » en tant que paramètre, lorsque nous utilisons des crochets doubles autour d’authors.url, Camel est capable de remplacer la valeur de application.properties, le fichier doit donc contenir la valeur de l’URL, par exemple :

    #application.properties
    
    authors.url=localhost:8081

    C’est tout ce dont nous avons besoin pour cette route. La réponse du point de terminaison de l’API Authors est renvoyée directement depuis l’application Camel.

    Enrichir et regrouper les réponses des auteurs et des livres

    La route direct:call-rest-author recherche l’auteur par son nom et nous utilisons la réponse pour récupérer l’identifiant de l’auteur, après avoir enrichi la réponse avec les livres de l’auteur, selon l’image :

    Le code de l’itinéraire est le suivant :

    from("direct:call-rest-author")
      .routeId("call-rest-services")
      .to("direct:author-service")
        .process(new GetAuthorIdProcessor())
      .enrich("direct:books-service", new JsonRestCallsAggregator());

    Approchons les parties individuellement :

    from("direct:author-service")
      .routeId("author-service")
      .removeHeaders("CamelHttp*")
      .setHeader(Exchange.HTTP_METHOD, constant("GET"))
    .toD("http://{{authors.url}}/authors/${header.name}");

    Quand on appelle le /integration/authors/{name} endpoint à partir de notre application Camel, le nom passé en tant que chemin devient disponible en tant qu’en-tête de l’échange (par exemple : /integration/authors/jr-tolkien; /integration/authors/jane-austin), car le chemin est variable en fonction du nom, nous devons utiliser .toD au lieu de la méthode .to.

    La réponse de l’API de l’auteur est un JSON avec les informations de l’auteur, pour récupérer l’identifiant, nous pouvons analyser ce JSON, mais il se trouve encapsulé dans le message d’échange, que Camel utilise pour transmettre des données entre les intégrations. Dans le composant http, la réponse est stockée dans le corps du message In, comme l’image suivante :

    Plus de détails sur l’échange peuvent être trouvés dans le JavaDoc : (https://www.javadoc.io/doc/org.apache.camel/camel-api/latest/org/apache/camel/Exchange.html) ou dans le Livre Camel in Action (https://livebook.manning.com/book/camel-in-action-second-edition).

    public class GetAuthorIdProcessor implements Processor {
         @Override
         public void process(Exchange exchange) throws Exception {
            String author = exchange.getIn().getBody(String.class);
            JsonParser parser = JsonParserFactory.getJsonParser();
            Map<String, Object> jsonMap = parser.parseMap(author);
            String authorId = (String) jsonMap.get("id");   
    
            exchange.getIn().setHeader("id", authorId);
            exchange.getIn().setBody(author);
        }
    }

    La méthode process est chargée de lire la réponse API des auteurs, qui se trouve dans le corps du message In. Pour analyser le json, nous utilisons certaines classes disponibles dans le framework Spring Boot. Après avoir récupéré l’ID, nous créons un en-tête avec l’identifiant de nom et redéfinissons la réponse de l’auteur JSON dans le corps du message In.

    • enrich("direct:books-service", new JsonRestCallsAggregator()): Cette ligne est chargée de faire l’appel de l’API du livre et d’agréger les réponses (auteur et livres) dans la classe `JsonRestCallsAggregator`.

    from("direct:books-service")
      .routeId("books-service")
      .removeHeaders("CamelHttp*")
      .setHeader(Exchange.HTTP_METHOD, constant("GET"))
    .toD("http://{{books.url}}/books/${header.id}");

    Semblable à la direct:author-service call, nous utilisons le composant http pour appeler l’API book. Parce que le point de terminaison reçoit un identifiant dans le chemin, nous utilisons celui que nous extrayons de la réponse des auteurs dans le process(new GetAuthorIdProcessor()), comme dans l’image suivante :

    La valeur {{books.url}} doit être déclaré dans application.properties, comme par exemple :

    #application.properties
    authors.url=localhost:8081
    books.url=localhost:8082

    La classe responsable de l’agrégation des réponses implémente org.apache.camel.AggregationStrategy:

    public class JsonRestCallsAggregator implements AggregationStrategy {
        @Override
        public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
            JsonParser parser = JsonParserFactory.getJsonParser();
    
            String books = newExchange.getIn().getBody(String.class);
            String author = oldExchange.getIn().getBody(String.class);       
    
            JsonObject authorJson = new JsonObject(parser.parseMap(author));        
            authorJson.put("books", new JsonArray(parser.parseList(books)));
    
            newExchange.getIn().setBody(authorJson.toJson());
            return newExchange;
        }
    }

    La méthode d’agrégation a deux paramètres, l’échange avant et après l’invocation d’enrichissement. En utilisant les classes Spring Boot pour analyser et manipuler JSON, nous pouvons récupérer l’auteur JSON (oldExchange) et agréger avec les livres de l’auteur JSON (newExchange), comme dans l’image :

    Notre agrégation de réponses générera une réponse finale JSON au format suivant :

    {
        "author": {
            "id": "...",
            "name": "...",
            "fullName": "...",
            "books": [ ... ]
        }
    }

    Échec de la gestion

    Avec notre application Camel en cours d’exécution, nous pouvons appeler le point de terminaison /integration/authors/{name}, et l’application va appeler les deux API et agréger le résultat. Mais que se passe-t-il si nous avons une défaillance dans l’une des API ?

    Voyons deux cas et refactorisons notre route Camel pour gérer ces échecs.

    Scénarios d’échec

    Échec de l’API de réservation : dans notre scénario, si nous appelons le point de terminaison de l’API de réservation (/books/{authorId}) à l’aide d’un authorId qui n’a pas de livres enregistrés, l’API répondra avec 404…

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.