Vous êtes sur la page 1sur 8

Architecture Microservice

L’architecture microservices propose une solution en principe très simple : découper une application en petits services,
appelé Microservices, parfaitement autonomes, qui exposent une API REST que les autres microservices pourront
consommer.

Architecture Microservice 1
Chaque microservice est parfaitement autonome :
Chaque microserive a sa propre base de donnée, son propres serveur (Ex: Tomcat), ses propres librairies, etc.
La plupart du temps, ces microservices sont chacun dans un contenair Docker, isl sont donc totalement indépendant, y
compris vis-à-vis de la machine sur laquelle ils tournent.

Voici une vue plus détaillée de notre architecture :

Du fait du cloisonnement complet de no.s microservice on peut utiliser dans chacun la technologie que l’on veut. Le
microservice A peut être Java tandis que le microservice B est en C++ ou Node.js, l’essentiel étant qu’ils exposent une API
REST permettant d’interagir avec eux. Ceci vas nous permettre de profiter des avancés technologique sans limite de langage,
de Framework, d’environnement, etc.

Grâce aux microservice, les équipes de développement deviennent beaucoup plus autonome car tu ne sera plus obliger de
consulter l’ensemble de l’équipe pour concrétiser une idée et vérifier sa compatibilité technique avec ce font les autres. Les
équipes vont donc être autonome et aller au bout de leurs idées en utilisant la technologie de leurs choix.

Architecture Microservice 2
Les services dans l'architecture Microservices sont très spécialisés. Ils s'occupent d'une et d'une seule fonctionnalité. Dans la
MSA (MicroService Architecture), le couplage faible est primordial, à savoir que chaque microservice doit être très
indépendant à tous les niveaux. Chaque microservice possède sa propre base de données, néanmoins, on peut
rencontrez une MSA où il y a une base de données partagée.

Les microservices se base majoritairement sur l’architecture REST mais peuvent fonctionner avec tout type d’architecture
comme SOAP (Simple Object Access Protocol).

La MSA tend à obligé à utiliser un seul protocole et à s’y tenir, on a bien sûr moins de liberté.

ResponseEntity :

Using ResponseEntity in Spring


ResponseEntity, RequestEntity are used in Spring REST apis, RequestEntity is used as method level
argument and ResponseEntity is used as method response. Both of these, can wrap any type of bean as
HTTP body and provides out of the box features. In this article, we will discuss about the ResponseEntity &
https://technicalsand.com/using-responseentity-in-spring

ResponseEntity est une classe qui hérite de HttpEntity, qui permet de retourner le code HTTP à retourner. L'intérêt de
ResponseEntity est de nous donner la main pour personnaliser le code facilement.
ResponseEntity est une extension de HttpEntity qui représente une réponse HTTP comprenant le statut, les en-têtes et le
corps. ResponseEntity vous permet de modifier la réponse avec des en-têtes et un code d'état facultatifs.

ResponseEntity.HeadersBuilder (Spring Framework 6.0.11 API)


declaration: package: org.springframework.http, class: ResponseEntity, interface: HeadersBuilder
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.HeadersBuilder.html

Codes de réponse HTTP - HTTP | MDN


Les codes de statut de réponse HTTP indiquent si une requête HTTP a été exécutée avec succès ou non.
Les réponses sont regroupées en cinq classes :

https://developer.mozilla.org/fr/docs/Web/HTTP/Status

Constructeurs ResponseEntity Objectif et


Types de constructeurs ResponseEntity
exemple

Crée une nouvelle ResponseEntity avec le code


ResponseEntity (état HttpStatus) d'état donné uniquement, sans en-tête ni corps.
Exemple : new ResponseEntity(HttpStatus. OK );

Crée une nouvelle HttpEntity avec les en-têtes et le


ResponseEntity (en-têtes code d'état donnés et sans aucun contenu de corps.
MultiValueMap<String,String>, statut HttpStatus) Exemple : new ResponseEntity(responseHeaders,
HttpStatus. NO_CONTENT );

Crée une nouvelle ResponseEntity avec le corps et le


code d'état donnés, et sans aucun en-tête. Exemple :
ResponseEntity (corps T, statut HttpStatus)
new ResponseEntity("Constructor example",
HttpStatus. NO_CONTENT );

Crée une nouvelle HttpEntity avec les en-têtes, le


ResponseEntity (corps T, en-têtes corps et le code d'état donnés Exemple : new
MultiValueMap<String,String>, statut HttpStatus) ResponseEntity("Exemple de constructeur",
responseHeaders, HttpStatus. NO_CONTENT );

ResponseEntity (Spring Framework 6.0.11 API)


declaration: package: org.springframework.http, class: ResponseEntity
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html

Architecture Microservice 3
Exemple :

@RequestMapping("/handle")
public ResponseEntity<Category> handle() {
Category category = new Category();
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(category.getId())
.toUri();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(location);
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<Category>(category, responseHeaders, HttpStatus.CREATED);
}

@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(category.getId())
.toUri();
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
}

Filtrage statique :
La librairie Jackson, qui nous permet de convertir nos objet Java en JSON, nous offre l’annotation @JsonIgnore, qu’il faut
mettre au dessus des propriété que nous ne voulons pas voir apparaitre dans nos objet JSON.
Quand on a beaucoup de propriété à caché on peut utiliser l’annotation @JsonIgnoreProperties(value = {”propriété1”,
”propriété2”}) au dessus de la classe concerné.

Filtrage dynamique :
Que faire si nous souhaitons afficher une propriété ou non, en fonction de qui le demande ? Pour cela, nous utilisons le filtrage
dynamique, @JsonFilter("monFiltreDynamique"), au dessus de la classe concerné, puis on effectue les autres
configurations dans notre controller comme dans le code suivant.
Partons de l’exemple de code suivant de controller :

//Récupérer la liste des produits


@GetMapping("/products")
public MappingJacksonValue listeProduits() {
List<Product> produits = productRepository.findAll();
SimpleBeanPropertyFilter monFiltre = SimpleBeanPropertyFilter.serializeAllExcept("prixAchat");
FilterProvider listDeNosFiltres = new SimpleFilterProvider().addFilter("monFiltreDynamique", monFiltre);
MappingJacksonValue produitsFiltres = new MappingJacksonValue(produits);
produitsFiltres.setFilters(listDeNosFiltres);
return produitsFiltres;
}

Ce code stocke la liste des produits retournés par findAll dans une liste.
SimpleBeanPropertyFilter est une implémentation de PropertyFilter qui permet d'établir les règles de filtrage sur un Bean
donné. Ici, nous avons choisi la règle serializeAllExcept qui exclut uniquement les propriétés que nous souhaitons ignorer.
Inversement, nous pouvons procéder avec la méthode filterOutAllExcept qui marque toutes les propriétés comme étant à
ignorer, sauf celles passées en argument.
Maintenant que nous avons établi notre règle de filtrage, la ligne suivante nous permet d'indiquer à Jackson à quel Bean
l'appliquer. Nous utilisons SimpleFilterProvider pour déclarer que les règles de filtrage que nous avons créées (monFiltre)
peuvent s'appliquer à tous les Beans qui sont annotés avec monFiltreDynamique.
Jusqu'à présent, nous n'avons encore rien filtré concrètement ! Nous avons établi la règle et indiqué que cette règle ne
s'applique qu'aux Beans qui sont annotés avec monFiltreDynamique, mais nous ne l'avons pas encore appliquée. Pour cela,
nous les mettons au format MappingJacksonValue. Cela permet de donner accès aux méthodes qui nous intéressent, comme
setFilters qui applique les filtres que nous avons établis à la liste de Product.

Architecture Microservice 4
Nous retournons ensuite la liste filtrée. MappingJacksonValue n'est qu'un simple "conteneur" qui ne change absolument rien
au contenu. MappingJacksonValue est donc exactement comme produits, avec des méthodes de filtrage en plus.

JpaRepository Keywords :
Keyword Sample JPQL snippet
… where x.lastname = ?1 and
And findByLastnameAndFirstname
x.firstname = ?2

… where x.lastname = ?1 or
Or findByLastnameOrFirstname
x.firstname = ?2

… where x.startDate between


Between findByStartDateBetween
1? and ?2

LessThan findByAgeLessThan … where x.age < ?1

GreaterThan findByAgeGreaterThan … where x.age > ?1

After findByStartDateAfter … where x.startDate > ?1

Before findByStartDateBefore … where x.startDate < ?1

IsNull findByAgeIsNull … where x.age is null

IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null

Like findByFirstnameLike … where x.firstname like ?1

… where x.firstname not like


NotLike findByFirstnameNotLike
?1

… where x.firstname like ?


StartingWith findByFirstnameStartingWith 1 (parameter bound with
prepended % )
… where x.firstname like ?
ngWith findByFirstnameEndingWith 1 (parameter bound with
appended % )
… where x.firstname like ?
Containing findByFirstnameContaining 1 (parameter bound wrapped
in % )
… where x.age = ?1 order by
OrderBy findByAgeOrderByLastnameDesc
x.lastname desc

Not findByLastnameNot … where x.lastname <> ?1

findByAgeIn(Collection<Age>
In … where x.age in ?1
ages)

findByAgeNotIn(Collection<Age>
NotIn … where x.age not in ?1
age)

True findByActiveTrue() … where x.active = true

False findByActiveFalse() … where x.active = false

Source :

Spring Data JPA - Reference Documentation


https://docs.spring.io/spring-data/data-jpa/docs/1.1.x/reference/html/#jpa.query-methods.query-creation

Requête JPQL :
Exemple :

@Query("SELECT id, nom, prix FROM Product p WHERE p.prix > :prixLimit")

List<Product> chercherUnProduitCher(@Param("prixLimit") int prix);

En paramètre de l'annotation, nous plaçons tout simplement notre requête JPQL. L'annotation @Param permet de spécifier le
nom du paramètre que nous allons recevoir. Cette annotation est optionnelle. Si elle n'est pas utilisée, l'ordre dans lequel les

Architecture Microservice 5
arguments sont fournis est utilisé. Nous aurons alors une requête de type :

SELECT id, nom, prix FROM Product p WHERE p.prix > ?1

Les Exceptions :
La gestions des exceptions est essentielle pour le bon fonctionnement de notre application.
Prenons un exemple dans le cas où nous ne trouvons pas un produit demander par l’utilisateur. L’API doit lever une exception
pour indiquer que le produit n’est pas trouver et renvoyer le code de statues correspondant.

@GetMapping(value = "/Produits/{id}")
public Product afficherUnProduit(@PathVariable int id) {
Product produit = productDao.findById(id);
if(produit==null) throw new ProduitIntrouvableException("Le produit avec l'id " + id + " est INTROUVABLE. Écran Bleu si je pouvai
return produit;
}

Si la variable produits est null, nous lançons une exception ProduitIntrouvableException. En effet, nous allons créer notre
propre exception afin d'être le plus spécifique possible.

Nous allons crée un package exceptions qui va contenir tous nos exceptions personnalisé et s’est dans ce package que nous
mettrons notre exception ProduitIntrouvableException, annoté avec @ResponseStatus pour renvoyer le bon code de
statues. ProduitIntrouvableException doit hériter RuntimeException pour que Spring Boot considère qu’il s’agit d’une classe
exception.

package com.ecommerce.microcommerce.web.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)

public class ProduitIntrouvableException extends RuntimeException


{
public ProduitIntrouvableException(String s)
{
super(s);
}
}

HttpStatus (Spring Framework 6.0.11 API)


declaration: package: org.springframework.http, enum: HttpStatus
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.html

Validations :
Spring propose de valider les données grâce à une dépendance spring-boot-starter-validation.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.6.0</version>
</dependency>

Cette librairie va nous permettre de valider les données grâce à de simples annotations, comme @Size, @NotNull, etc.

Impact sur les méta-


Annotation S'applique à Vérification à l'exécution
données d'Hibernate

@Length(min=, max=) propriété (String) vérifie si la longueur de la la longueur de la colonne


chaîne de caractères est sera positionnée à max

Architecture Microservice 6
Impact sur les méta-
Annotation S'applique à Vérification à l'exécution
données d'Hibernate
comprise dans l'intervalle

propriété (nombre ou
vérifie si la valeur est ajoute une contrainte de
@Max(value=) chaîne de caractères
inférieure ou égale à max vérification sur la colonne
représentant un nombre)

propriété (nombre ou
vérifie si la valeur est ajoute une contrainte de
@Min(value=) chaîne de caractères
supérieure ou égale à max vérification sur la colonne
représentant un nombre)

vérifie si la valeur n'est les colonnes sont


@NotNull propriété
pas nulle marquées "not null"

propriété (Date ou vérifie si la date est dans ajoute une contrainte de


@Past
Calendar) le passé vérification sur la colonne

propriété (Date ou vérifie si la date est dans


@Future aucun
Calendar) le futur

vérifie si la propriété
correspond à l'expression
@Pattern(regex="regexp",
propriété (String) rationnelle donnée (pour aucun
flag=)
"flag",
voir java.util.regex.Pattern)

propriété (nombre ou vérifie si la valeur est


ajoute une contrainte de
@Range(min=, max=) chaîne de caractères comprise entre min et max
vérification sur la colonne
représentant un nombre) (inclus)

vérifie si la taille de
propriété (tableau,
@Size(min=, max=) l'élément est comprise aucun
collection, map)
entre min et max (inclus)

vérifie que la méthode est


évaluée à faux (utile pour
@AssertFalse propriété les contraintes exprimées aucun
dans le code plutôt que
dans les annotations)

vérifie que la méthode est


évaluée à vrai (utile pour
@AssertTrue propriété les contraintes exprimées aucun
dans le code plutôt que
dans les annotations)

exécute la validation
récursivement sur l'objet
associé. Si l'objet est une
Collection ou un tableau,
@Valid propriété (objet) les éléments sont validés aucun
récursivement. Si l'objet
est une Map, les éléments
valeur sont validés
récursivement.

vérifie si la chaîne de
caractères est conforme à
@Email propriété (String) aucun
la spécification d'une
adresse e-mail

Sources :

Chapitre 4. Hibernate Validator


Les annotations sont une manière très commode et élégante pour spécifier
des contraintes invariantes sur un modèle de données. Vous pouvez, par
exemple, indiquer qu'une propriété ne devrait pas être nulle, que le solde
https://docs.jboss.org/hibernate/annotations/3.4/reference/fr/html/validator.html

Architecture Microservice 7
Hibernate Validator 8.0.1.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
Hibernate Validator, Annotation based constraints for your domain model - Reference Documentation
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#preface

Il nous faut également indiquer dans notre contrôleur que le produit reçu de l'utilisateur est à valider. Pour ce faire, il faut ajouter
l'annotation @Valid , comme illustré ci-après :

public ResponseEntity<Void> ajouterProduit(@Valid @RequestBody Product product)


{
....
}

ResponseEntity est très souvent utiliser comme type de retour de nos réponse HTTP. Exemple: ResponseEntity<Produc>
getProduct();
NB: il est conseillé d’ajouter dans le header de notre réponse http la localisation de la nouvelle ressource qui vient d’être créer,
ie que si je crée un nouveau produit par exemple dans ma base de données, si la création a été un succès je dois fournir l’URL
permettant d’accéder à mon nouveau produit créer. Exemple:

URI location = ServletUriComponentsBuilder


.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(productAdded.getId())
.toUri();
return ResponseEntity.created(location).build();

Ici, la méthode qui permet de créer un nouveau produit retourne un objet ResponseEntity<Product>, tu sais déjà pourquoi 😉.
La méthode build() permet de construire le header de notre réponse HTTP.

Architecture Microservice 8

Vous aimerez peut-être aussi