Date de première publication : 2026/01/07
L'objectif de ce TP est d'exposer une API REST (de type HATEOAS) de données stockées dans une base non relationnelles comme MongoDB.
Les données exposées concernent la gestion de collections/d'albums de "billets souvenir".
Mongo DB
Les machines à l'ISIMA sont configurées pour vous permettre d'utiliser docker. Si vous voulez travailler sur votre propre machine, il vous faudra installer ce qu'il faut. Par exemple, sous MacOS, il faut installer Docker Desktop
Pour utiliser docker à l'ISIMA, vous devez toutefois lancer :
docker_rootless_init.sh
docker pull mongo:latest
docker run -d \
--name mongodb \
-p 27017:27017 \
-v mongodb_data:$HOME/Documents/MONGO \
mongo:latest
Voici quelques commandes docker pour la gestion de votre image :
docker ps
docker stop mongodb
docker start mongodb
docker rm mongodb # donnees conservees
docker volume rm mongodb_data # suppression des donnees
J'aime bien manipuler la base MongoDB en ligne avec le shell :
docker exec -it mongodb mongosh
Voici quelques commandes :
show dbs
use base
show collections
db.types.deleteMany({});
db.collections.find();
Vous pouvez également installer Mongo DB Compass qui propose une interface graphique pour manipuler les "bases"
Mise en place du projet
Il faut créer un nouveau projet Spring Boot et choisir les options suivantes :
On a sélectionné les options suivantes :
- Project : Gradle - groovy - le logiciel d'automatisation
- Langage : Java
- Spring Boot : 4.0.1 - la version stable la plus récente
- Dependencies
- Spring Boot DevTools
- Data Rest
- Data Mongo
- Lombok
- Project Metadata
- Group : app
- Artifact : ZZouvenir
- Name : ZZouvenir
- Package name : app
- Java : 17
Dans le fichier application.properties, il faudra dire quelle base utiliser (on peut spécifier utilisateur et mot de passe entre autres) :
spring.mongodb.uri=mongodb://localhost:27017/zzouvenir
Nous allons avoir besoin de décrire les données à mettre en base :
- BilletType : la base de données des types de billet. On se contentera de les identifier par une amorce et une année (même si on sait que cela ne suffit pas)
- Album/Collection : un album aura un nom et comportera une liste de billets.
- Billet : chaque billet a un type et un numéro pour en faire quelque chose d'unique
Avec les options SpringBoot choisies, toutes les classes sont des Document - les instances peuvent être exposées.
Chaque document a besoin d'un identifiant , soit au travers d'un attribut annoté @Id, soit un champ _id calculé automatiquement par MongoDB.
La base MongoDB ne gère pas les relations comme pourrait le faire une base SQL et notamment les suppressions en cascade par exemple.
On peut gérer la notion de "clé étrangère" avec les annotations @DocumentReference (NOSQL - à privilégier), @DBRef (NOSQL) ou encore @OneToMany (objet).
Voici donc un squelette de code pour gérer tout cela : (n'hésitez pas à utiliser Lombok pour générer les méthodes)
import org.springframework.data.annotation.Id;
class BilletType {
@Id
String id;
String annee;
String amorce;
public BilletType(String annee, String amorce) {
this.id = annee+amorce;
this.annee = annee;
this.amorce = amorce;
}
import org.springframework.data.annotation.Id;
import java.util.*;
class Album {
@Id
String id;
List<Billet> billets;
public Album(String id) {
this.id = id;
billets = new ArrayList<Billet>();
}
public void add(Billet billet) {
billets.add(billet);
}
}
Pour finir, la classe Billet :
class Billet {
String id;
BilletType type;
String numero;
public Billet(BilletType type, String numero) {
this.id = type.getId()+numero;
this.type = type;
this.numero = numero;
}
}
Il faut encore écrire les repositories BilletTypeRepository et AlbumRepository
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
// annotation optionnelle, sauf si on veut changer le nom de publication
@RepositoryRestResource(collectionResourceRel = "types", path = "types")
public interface BilletTypeRepository extends MongoRepository {
}
On doit encore tester que cela marche. Créons quelques données :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ZZouvenirApplication implements CommandLineRunner {
@Autowired
BilletTypeRepository types;
@Autowired
AlbumRepository albums;
public static void main(String[] args) {
SpringApplication.run(ZZouvenirApplication.class, args);
}
@Override
public void run(String... strings) throws Exception {
albums.deleteAll();
types.deleteAll();
BilletType type1 = new BilletType("2024", "AECG");
BilletType type2 = new BilletType("2023", "FDSSS");
types.save(type1);
types.save(type2);
Album album = new Album("loic");
Billet billet = new Billet(type1, "000001");
album.add(billet);
album.add(new Billet(type2, "000002"));
albums.save(album);
System.out.println("BilletTypes found with findAll():");
System.out.println("-------------------------------");
for (BilletType btype : types.findAll()) {
System.out.println(btype);
}
}
}
On peut vérifier que la base est bien peuplée avec CURL ou un navigateur :
curl http://localhost:8080
curl http://localhost:8080/types
curl http://localhost:8080/albums
curl http://localhost:8080/albums/loic
curl -i -X POST -H "Content-Type:application/json" -d "{ \"id\" : \"autre\" }" http://localhost:8080/albums
Par défaut, tous les repositories sont publiés. On peut se limiter à ceux qui sont annotés avec
@RepositoryRestResource, il faut alors ajouter la configuration suivante :
spring.data.rest.detection-strategy=annotated
On peut aussi interdire un type d'action à réaliser, soit en écrivant une configuration :
@Configuration public class RestConfig implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.getExposureConfiguration()
.forDomainType(BilletType.class) .withItemExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.DELETE))
.withCollectionExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.DELETE));
}
}
soit en annotant un repository :
@RepositoryRestResource
public interface BilletTypeRepository extends ... {
@Override
@RestResource(exported = false)
void deleteById(String id);
@Override
@RestResource(exported = false)
void delete(BilletTypeRepository entity);
}
Allez plus loin
Il faudrait maintenant sécuriser l'API pour que seuls certains utilisateurs (avec des rôles) puissent accéder aux informations.
Liens
- Tutoriel mongo DB
- Tutorial Mongo DB Datat Rest/li>
- Configuration pour REST
- Sécurité JWT
- Lien pour le starter


