Exercice - Créer une application Quarkus

Effectué

Dans cette unité, vous créez une application Quarkus de base. Vous utilisez Maven pour démarrer l’application, et l’environnement de développement intégré (IDE) de votre choix pour modifier le code. Utilisez un terminal de votre choix pour exécuter le code. Vous utilisez Docker pour démarrer une base de données PostgreSQL locale afin de pouvoir exécuter et tester l’application localement.

Générer l’application Quarkus avec Maven

Vous pouvez générer une structure de projet Quarkus de plusieurs façons. Vous pouvez utiliser l’interface web Quarkus, un plug-in d’IDE ou le plug-in Quarkus Maven. Utilisons le plug-in Maven pour générer la structure du projet.

Vous générez votre application avec plusieurs dépendances :

  • La dépendance resteasy pour exposer un point de terminaison REST
  • La dépendance jackson pour sérialiser et désérialiser le code JSON
  • La dépendance hibernate pour interagir avec la base de données
  • La dépendance postgresql pour se connecter à la base de données PostgreSQL
  • La dépendance docker pour créer une image Docker

Vous n’avez pas besoin de spécifier les dépendances Azure, car vous exécutez d’abord votre application localement, puis en déployez une version conteneurisée sur Azure Container Apps.

À l’invite de commandes, générez l’application de tâches :

mvn -U io.quarkus:quarkus-maven-plugin:3.7.3:create \
    -DplatformVersion=3.7.3 \
    -DprojectGroupId=com.example.demo \
    -DprojectArtifactId=todo \
    -DclassName="com.example.demo.TodoResource" \
    -Dpath="/api/todos" \
    -DjavaVersion=17 \
    -Dextensions="resteasy-jackson, hibernate-orm-panache, jdbc-postgresql, docker"

Cette commande crée un projet Quarkus. Elle génère une structure de répertoires Maven (src/main/java pour le code source et src/test/java pour les tests). Elle crée des classes Java, des tests et des Dockerfiles. Elle génère également un fichier pom.xml avec toutes les dépendances nécessaires (Hibernate, RESTEasy, Jackson, PostgreSQL et Docker) :

  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-orm-panache</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-jdbc-postgresql</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-container-image-docker</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-hibernate-orm</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

Remarque

Toutes les dépendances dans le fichier pom.xml sont définies dans la nomenclature Quarkus io.quarkus.platform:quarkus-bom.

Coder l’application

Ensuite, renommez la classe MyEntity.java générée en Todo.java (située dans le même dossier que le fichier TodoResource.java). Remplacez le code existant par le code Java suivant. Elle utilise l’API de persistance Java (package jakarta.persistence.*) pour stocker et récupérer les données de votre serveur PostgreSQL. Elle utilise également Hibernate ORM avec Panache (héritage de io.quarkus.hibernate.orm.panache.PanacheEntity) pour simplifier la couche de persistance.

Vous utilisez une entité JPA (@Entity) pour mapper directement l’objet Java Todo à la table Todo PostgreSQL. Le point de terminaison REST TodoResource crée ensuite une classe d’entité Todo et la rend persistante. Cette classe est un modèle de domaine qui est mappé à la table Todo. Le tableau est créé automatiquement par JPA.

L’extension de PanacheEntity vous permet d’obtenir un certain nombre de méthodes de création, de lecture, de mise à jour et de suppression (CRUD) génériques pour votre type. Vous pouvez donc effectuer des opérations comme l’enregistrement et la suppression d’objets Todo dans une seule ligne de code Java.

Ajoutez le code suivant à l’entité Todo :

package com.example.demo;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

import jakarta.persistence.Entity;
import java.time.Instant;

@Entity
public class Todo extends PanacheEntity {

    public String description;

    public String details;

    public boolean done;

    public Instant createdAt = Instant.now();

    @Override
    public String toString() {
        return "Todo{" +
                "id=" + id + '\'' +
                ", description='" + description + '\'' +
                ", details='" + details + '\'' +
                ", done=" + done +
                ", createdAt=" + createdAt +
                '}';
    }
}

Pour gérer cette classe, mettez à jour la classe TodoResource pour publier des interfaces REST afin de stocker et récupérer des données en utilisant HTTP. Ouvrez la classe TodoResource et remplacez le code par le suivant :

package com.example.demo;

import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo;
import org.jboss.logging.Logger;

import java.util.List;

@Path("/api/todos")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public class TodoResource {

    @Inject
    Logger logger;

    @Inject
    UriInfo uriInfo;

    @POST
    @Transactional
    public Response createTodo(Todo todo) {
        logger.info("Creating todo: " + todo);
        Todo.persist(todo);
        UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder().path(todo.id.toString());
        return Response.created(uriBuilder.build()).entity(todo).build();
    }

    @GET
    public List<Todo> getTodos() {
        logger.info("Getting all todos");
        return Todo.listAll();
    }
}

Exécution de l'application

Lorsque vous exécutez l’application en mode développement, Docker doit être en cours d’exécution. En effet, Quarkus détecte que vous avez besoin d’une base de données PostgreSQL (en raison de la dépendance PostgreSQL quarkus-jdbc-postgresql déclarée dans le fichier pom.xml), télécharge l’image Docker PostgreSQL et démarre un conteneur avec la base de données. Il crée ensuite automatiquement la table Todo dans la base de données.

Vérifiez que Docker s’exécute localement sur votre machine et exécutez l’application de tâches avec cette commande :

cd todo
./mvnw quarkus:dev    # On Mac or Linux
mvnw.cmd quarkus:dev  # On Windows

L’application Quarkus démarre et se connecte à votre base de données. Vous devez normalement voir la sortie suivante :

[io.qua.dat.dep.dev.DevServicesDatasourceProcessor] Dev Services for the default datasource (postgresql) started.
[io.qua.hib.orm.dep.HibernateOrmProcessor] Setting quarkus.hibernate-orm.database.generation=drop-and-create to initialize Dev Services managed database
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) SQL Warning Code: 0, SQLState: 00000

[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) table "todo" does not exist, skipping
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) SQL Warning Code: 0, SQLState: 00000
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) sequence "hibernate_sequence" does not exist, skipping
[io.quarkus] (Quarkus Main Thread) todo 1.0.0-SNAPSHOT on JVM (powered by Quarkus) started in 4.381s. Listening on: http://localhost:8080
[io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
[io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-postgresql, narayana-jta, resteasy, resteasy-jackson, smallrye-context-propagation, vertx]

--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>

Pour tester l’application, vous pouvez utiliser cURL.

Dans un terminal distinct, créez un élément de tâche dans la base de données avec la commande suivante. Vous devez voir le journal dans la console Quarkus :

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done": "true"}' \
    http://127.0.0.1:8080/api/todos

Cette commande doit retourner l’élément créé (avec un identificateur) :

{"id":1,"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done":true,"createdAt":"2022-12-30T15:17:20.280203Z"}

Créez une deuxième tâche en utilisant la commande cURL suivante :

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"Take Azure Container Apps MS Learn","details":"Take the ACA Learn module","done": "false"}' \
    http://127.0.0.1:8080/api/todos

Ensuite, récupérez les données à l’aide d’une nouvelle requête cURL :

curl http://127.0.0.1:8080/api/todos

Cette commande renvoie la liste des éléments de tâche, y compris les éléments que vous avez créés :

[ 
  {"id":1,"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done":true},
  {"id":2,"description":"Take Azure Container Apps MS Learn","details":"Take the ACA Learn module","done":false}
]

Test de l’application

Pour tester l’application, vous pouvez utiliser la classe existante TodoResourceTest. Il doit tester le point de terminaison REST. Pour tester le point de terminaison, il utilise RESTAssured. Remplacez le code dans la classe TodoResourceTest par le code suivant :

package com.example.demo;

import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import static jakarta.ws.rs.core.HttpHeaders.CONTENT_TYPE;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import org.junit.jupiter.api.Test;

@QuarkusTest
class TodoResourceTest {

    @Test
    void shouldGetAllTodos() {
        given()
                .when().get("/api/todos")
                .then()
                .statusCode(200);
    }

    @Test
    void shouldCreateATodo() {
        Todo todo = new Todo();
        todo.description = "Take Quarkus MS Learn";
        todo.details = "Take the MS Learn on deploying Quarkus to Azure Container Apps";
        todo.done = true;

        given().body(todo)
                .header(CONTENT_TYPE, APPLICATION_JSON)
                .when().post("/api/todos")
                .then()
                .statusCode(201);
    }
}

Lorsque vous testez l’application, Docker Desktop doit être en cours d’exécution parce que Quarkus détecte qu’il a besoin de la base de données PostgreSQL pour les tests. Testez l’application en utilisant cette commande :

./mvnw clean test    # On Mac or Linux
mvnw.cmd clean test  # On Windows

La sortie doit ressembler à ceci :

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.example.demo.TodoResourceTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------