An open API service indexing awesome lists of open source software.

https://github.com/gip-recia/menu-cantine-web-service

API pour les menus de la cantine des collèges et lycées de la région
https://github.com/gip-recia/menu-cantine-web-service

Last synced: 3 months ago
JSON representation

API pour les menus de la cantine des collèges et lycées de la région

Awesome Lists containing this project

README

        

# Menu Cantine Web Service

Ce projet spring boot est la partie **back-end** du service Menu Cantine. Les technologies principalement utilisées ainsi que leurs versions sont données dans la liste suivante :
- spring-boot 2.7.17
- spring-security 5.7.11
- junit 4.13.2
- ehcache 2.10.9.2

# Architecture

## Structure générale

Les différents fichiers du projet sont structurés de la manière suivante :
```
.
├── src # Contient les sources java et les fichiers de ressources
│ ├── main
│ │ ├── java
│ │ │ ├── fr.recia.menucatine # Contient le code métier
│ │ │ └── META-INF
│ │ ├── resources # Contient les fichiers de config par défaut et de ressources
│ │ │ ├── application.yml
│ │ │ ├── application-unit.yml
│ │ │ ├── logback.xml
│ │ │ ├── ehcache.xml
│ │ │ ├── demo # Contient une version du front déjà compilée pour faire des tests en local
│ │ │ │ ├── demo.html
│ │ │ │ ├── menu-cantine.js
│ │ │ │ └── ...
│ │ │ ├── img # Contient les images (pour les logos des labels) à afficher
│ │ │ │ └── ...
│ │ │ └── ... # Autres fichiers de ressources
│ └── test # Contient les fichiers java pour les tests unitaires
│ └── ...
├── target # Contient les classes compilées
│ └── ..
├── pom.xml # Pom du projet
└── README.md
└── ...
```

## Code métier

Le package `fr.recia.menucatine` est lui structuré de la manière suivante :

```
.
├── adoria
│ ├── beans # Contient les objets de l'ancien back envoyés au front
│ │ ├── Journee.java
│ │ ├── Plat.java
│ │ ├── Service.java
│ │ └── ...

├── beans
│ ├── Requete.java # Objet requete envoyé depuis le front
│ ├── RequeteHelper.java # Classe utilitaire, utilisée pour les convertions de dates par exemple
│ └── Semaine.java # Objet semaine envoyé vers le front, consituté de adoria.beans

├── config # Configuration de la sécurité, du webclient, des services et des sous-menus
│ ├── CorsConfig.java
│ ├── EhCacheJmxConfiguration.java
│ ├── MapperConfig.java
│ ├── SecurityConfiguration.java
│ ├── SousMenuProperties.java
│ ├── UAIConfig.java
│ └── WebClientConfiguration.java

├── dto # Classes mappées depuis le JSON récupéré de l'API
│ ├── JourneeDTO.java # Objet construit à partir des deux classes ci-dessous
│ ├── PlatDTO.java # Représente un plat selon l'API
│ ├── LabelDTO.java # Représente un label (AOP, AOC, etc..) selon l'API
│ └── ServiceDTO.java # Représente un service selon l'API


├── exception # Les différentes exceptions personnalisées
│ ├── ResponseExceptionData.java # Représente les données envoyées au front lors de la levée d'une exception
│ ├── CustomMenuCantineException.java # Représente une exception custom levée par le programme
│ ├── NoDataExchangeException.java # Exception dans le cas ou le partage des données est désactivée
│ ├── UnknownUAIException.java # Exception dans le cas ou l'UAI est inconnu
│ └── WebgerestRequestException.java # Exception autre lors de la communication avec l'API

├── mapper # Permet de transformer les objets de la nouvelle API en objets de l'ancienne API
│ ├── IMapper.java
│ └── MapperWebGerest.java

├── webgerest
│ ├── APIClient.java # Classe permettant de communiquer avec l'API
│ ├── AuthResponse.java # Objet stockant une réponse à une demande d'authentification
│ ├── CacheKeyRequete.java # Objet servant de clé pour le cache des requêtes
│ └── DynamicURLResponse.java # Objet stockant une réponse à une demande d'url associée à un UAI

├── MenuCantineApplication.java # Classe principale permettant de lancer l'application
├── MenuCantineController.java # Controlleur de l'application
├── MenuCantineServices.java # Service appelé par le controlleur lors d'une requête
├── SecurityConfiguration.java # Configuration de spring-security
└── ...
```

## Ancien back

Le package `adoria.beans` définit les différents objets qui vont constituer une `Semaine`, qui sera l'objet final envoyé au front. Ces classes servent aussi à **effectuer certains calculs préalables** sur ces objets, tels que la suppression de services vides, la complétion avec des plats vides pour alignement, ect... Ces calculs sont gérés ici et non pas dans le service ou dans les DTO afin de bien séparer les différents composants. Ce sont notamment les méthodes `clean()` des différents objets ainsi que les classes `NbPlatParSsMenu` et `NbPlatParSsMenuParService` qui effectuent ces calculs.

## Cheminement d'une requête

Le **controlleur** commence par récupérer la requête faite depuis l'application. Celle-ci contient dans son `body` un objet `Requete` qui contient notamment la date et l'UAI du menu demandé. Le controlleur appelle alors le **service** pour qu'il construise un objet `Semaine`. Pour constuire cet objet, le service va faire appel à l'API.

Afin de faire une requête à l'API, plusieurs **opérations préalables** sont nécessaires :
- Récupérer **l'URL** sur laquelle on va faire la requête. Pour cela on doit faire une première requête sur une URL particulière avec l'UAI de l'établissement donc on veut récupérer le menu. Un **dictionnaire** associe les UAI déjà demandés à leur URL afin de ne pas avoir à refaire une requête à chaque fois.
- Récupérer le **token** pour s'authentifier lorsqu'on effectue la requête. Ce token est demandé sur l'URL récupérée ci-dessus avec un `client_secret` et un `client_id`. De la même manière, un **dictionnaire** associe les URL déjà demandés à leur token afin de ne pas avoir à refaire une requête à chaque fois.

Une fois ces deux éléments récupérés, on peut faire la requête à l'API. Pour cela on effectue un appel sur l'URL associée avec l'UAI avec le token dans le champ `Authorization`, et comme paramètres la `date`, `l'UAI` et le `numéro de service`. Pour récupérer une semaine entière, on doit donc faire **20 requêtes** (4 services pour 5 jours).

Le service regroupe tous les résultats de ces requêtes dans une `List`, et fait appel au **mapper** qui va transformer les objets récupérés depuis l'API en objets de l'ancienne API, afin de pouvoir les envoyer au front. Le service "nettoie" ensuite et complète l'objet `Semaine` renvoyé par le mapper en faisant appel aux méthodes `clean` et `complete` de la classe `Semaine`. Ensuite, le service peut retourner la `Semaine` au controlleur, qui peut enfin l'envoyer au front.

## Cache

L'application dispose d'un système de cache afin de ne pas trop solliciter l'API et d'améliorer le temps de réponse. Il existe 3 caches :
- Le cache `requetes` qui stocke les réponses de l'API pour les dates futures. Ce cache est renouvellé de temps en temps.
- Le cache `permanant` qui stocke les réponses de l'API pour les dates passées. Ce cache n'est pas renouvellé.
- Le cache `erreur` qui stocke les réponses en erreur de l'API. Ce cache est renouvellé très régulièrement.
- Le cache `token` qui stocke les échecs d'obtention d'un token pour une url donnée. Ce cache est renouvellé très régulièrement.

La logique du cache est gérée directement dans la classe `APIClient`. C'est elle qui va regarder si les objets sont dans le cache avant de faire les requêtes, et stocker les réponses de l'API dans le cache correspondant.

# Déploiement

## En Local

Avant tout, il faut commencer par compléter la configuration de l'application et notamment les informations relatives à l'API avec laquelle communiquer. Intellij est recommandé pour un lancement en local : il suffit d'ajouter une configuration d'application sur la classe `fr.recia.menucantine.MenuCantineApplication` après avoir ouvert le projet.
L'application est alors accessible sur l'URL suivante : `http://localhost:PORT/menuCantine/demo/demo.html`
Attention si on change la classe `ServiceDTO`, `PlatDTO` ou `LabelDTO` il faut bien penser à supprimer le cache avant de relancer l'application.

## Nouvelle version du front

Pour tester une nouvelle version du front avec le back, il suffit de copier les fichiers `.js` compilés dans le dossier `ressources/static/demo` (attention à ne pas toucher le fichier `demo.html` sauf si nécessaire).

## Constuire un war

Pour construire un war, il suffit de faire un simple `mvn clean package`.
Les tests unitaires seront lancés automatiquement, et le war sera disponible dans `target`.

## Pousser une snapshot

Pour push une snapshot, il suffit de faire un `mvn clean package deploy` (attention à bien vérifier dans le `pom.xml` qu'on est bien sur une version de test).

## Pousser une release

Pour push une release, on commence par un `mvn release:clean release:prepare`, puis on fait un `mvn realease:perfrom`.

## Gestion des licenses

Pour vérifier les entêtes de fichier : `mvn license:check`.
Pour ajouter les entêtes de fichier : `mvn license:format`.
Le template de la license ajoutée est dans `etc/header.template`.

# Configuration

La configuration par défaut se trouve dans le fichier `application.yml` dans les ressources. Elle doit **impérativement** être complétée avant de pouvoir lancer l'application, même en local. Il faut compléter au minimum les identifiants pour l'API.

| Propriété | Signification | Valeur par défaut |
|------------------------------------|-------------------------------------------------------------------------------------------------------------|-----------------------------------|
| server.port | Port du serveur | 80 |
| server.servlet.context-path | Path du servlet | /menuCantine |
| soffit.jwt.signatureKey | Clé pour le soffit | *à compléter* |
| adoria.gemrcn-csv | Chemin vers le fichier contenant les gemrcn à charger | classpath:GemRcn.csv |
| adoria.labels-csv | Chemin vers le fichier contenant les labels à charger | classpath:labels.csv |
| api.initial-query-url | URL complète de l'API sur laquelle on récupère une URL dynamique par UAI | https://api.webgerest.fr/url |
| api.auth-endpoint | Endpoint sur lequel on doit faire une requête pour s'authentifier | /auth |
| api.menu-endpoint | Endpoint sur lequel on doit faire une requête pour récupérer un menu | /menus |
| api.client_id | L'identifiant permettant de s'authentifier pour récupérer un token | *à compléter* |
| api.menu-endpoint | Le mot de passe permettant de s'authentifier pour récupérer un token | *à compléter* |
| logging.level.fr.recia.menucantine | Niveau de log en local | debug |
| spring.cache.type | La librairie utilisée pour la gestion du cache | ehcache |
| mapper.services | Un dictionnaire des services avec le nom et le numéro de chaque service | *à voir directement dans la conf* |
| mapper.sousmenus | Un dictionnaire des sous-menus avec le nom, le nom final et le numéro de chaque sous-menu | *à voir directement dans la conf* |
| uais.regroupement | Un dictionnaire associant un UAI à un autre (lorsque la clé est demandée, c'est la valeur qui sera utlisée) | *à compléter* |
| menucantine.demo | Si le mode démo locale est actif (uniquement pour les tests en local) | false |
| security.cors.enabled | Si le CORS est activé | false |
| security.cors.allowedOrigins | La liste des allowedOrigins pour la config du CORS | *à compléter* |
| security.cors.exposedHeaders | La liste des exposedHeaders pour la config du CORS | *à compléter* |
| security.cors.allowedHeaders | La liste des allowedHeaders pour la config du CORS | *à compléter* |
| security.cors.allowedMethods | La liste des allowedMethods pour la config du CORS | *à compléter* |

# Tests unitaires
Les tests unitaires sont lancés avec un profil `unit` qui utilise une configuration particulière `application-unit.yml` qui désactive le cache. Les différentes classes pour les tests sont les suivantes :
```
test
├── java
│ ├── beans # Tests sur les beans adoria (méthodes clean et complete)
│ │ ├── BeanJourneeTests.java
│ │ ├── BeanPlatTests.java
│ │ ├── BeanSemaineTests.java
│ │ └── BeanServiceTests.java
│ └── mapper # Tests de la transformation des DTO en beans adoria
│ │ └── MapperWebgerestTests.java
│ ├── MenuCantineApplicationTests.java
│ ├── MenuCantineControllerTests.java
│ └── MenuCantineServiceTests.java
```
On utilise `mockito` pour mocker les dépendances utiles lorsqu'on teste le service ou le controlleur. Dans le cadre du service, on mock les appels à l'API et au mapper, et dans le cas du controlleur, on map les appels au service.

Le rapport du coverage des tests unitaires est disponible sous `target/coverage-reports/jacoco-unit.exec`.