Esercizio - Creare un'applicazione Quarkus
In questa unità si creerà un'applicazione Quarkus di base. Per avviare l'applicazione si userà Maven e per modificare il codice si userà un ambiente di sviluppo integrato (IDE) di propria scelta. Usare un terminale di propria scelta per eseguire il codice. Per avviare un database PostgreSQL locale, si usa Docker, in modo da poter eseguire e testare l'applicazione attività in locale.
Generare l'applicazione Quarkus usando Maven
Esistono diversi modi per generare una struttura di progetto Quarkus. È possibile usare l'interfaccia Web Quarkus, un plug-in IDE o il plug-in Quarkus Maven. Si userà ora il plug-in Maven per generare la struttura del progetto.
L'applicazione viene generata con diverse dipendenze:
- La dipendenza
resteasy
per esporre un endpoint REST - La dipendenza
jackson
per serializzare e deserializzare JSON - La dipendenza
hibernate
per interagire con il database - La dipendenza
postgresql
per connettersi al database PostgreSQL - La dipendenza
docker
per compilare un'immagine Docker
Non è necessario specificare le dipendenze di Azure, perché prima si esegue l'applicazione in locale e poi si distribuisce una versione in contenitori in App contenitore di Azure.
Al prompt dei comandi, generare l'attività di applicazione:
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"
Questo comando crea un nuovo progetto Quarkus. Genera una struttura di directory Maven (src/main/java
per il codice sorgente e src/test/java
per i test). Crea alcune classi Java, alcuni test e alcuni Dockerfile. È stato anche generato un file pom.xml con tutte le dipendenze necessarie (Hibernate, RESTEasy, Jackson, PostgreSQL e 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>
Nota
Tutte le dipendenze nel file pom.xml sono definite nella distinta base (bill of materials) di Quarkus io.quarkus.platform:quarkus-bom
.
Codice dell'applicazione
Successivamente, rinominare la classe MyEntity.java generata in Todo.java (che si trova nella stessa cartella del fileTodoResource.java ). Sostituire il codice esistente con il codice Java seguente. Il codice usa Java Persistence API (pacchettojakarta.persistence.*
) per archiviare e recuperare dati dal server PostgreSQL. Usa anche Hibernate ORM con Panache (che eredita da io.quarkus.hibernate.orm.panache.PanacheEntity
) per semplificare il livello di persistenza.
Si userà un’entità (@Entity
) per eseguire il mapping dell’oggettoTodo
Java direttamente sulla tabella Todo
di PostgreSQL. Quindi, l’endpoint REST TodoResource
crea una nuova classe di entità Todo
e la rende persistente. Questa classe è un modello di dominio con mapping alla tabella Todo
. La tabella viene creata automaticamente da JPA.
Estendendo PanacheEntity
si ottengono diversi metodi generici di creazione, lettura, aggiornamento ed eliminazione (CRUD, Create, Read, Update, Delete) per il tipo. In questo modo è possibile eseguire operazioni come il salvataggio e l'eliminazione di oggetti Todo
in una sola riga di codice Java.
Aggiungere il codice seguente all’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 +
'}';
}
}
Per gestire tale classe, aggiornare il TodoResource
in modo che possa pubblicare interfacce REST per archiviare e recuperare i dati tramite HTTP. Aprire la classe TodoResource
e sostituire il codice con il seguente:
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();
}
}
Eseguire l'applicazione
Quando si esegue l'applicazione in modalità di sviluppo, Docker deve essere in esecuzione. Questo avviene perché Quarkus rileva che è necessario un database PostgreSQL (a causa della dipendenza PostgreSQL quarkus-jdbc-postgresql
dichiarata nel file pom.xml file), scarica l'immagine Docker PostgreSQL e avvia un contenitore con il database. Crea quindi automaticamente la tabella Todo
nel database.
Assicurarsi che Docker sia in esecuzione in locale nel computer ed eseguire l'applicazione dell’attività usando il comando seguente:
cd todo
./mvnw quarkus:dev # On Mac or Linux
mvnw.cmd quarkus:dev # On Windows
L'applicazione Quarkus verrà avviata e connessa al database. Verrà visualizzato l'output seguente:
[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>
Per testare l'applicazione, è possibile usare cURL.
In un terminale separato creare un nuovo elemento dell’attività nel database con il comando seguente. Verrà visualizzato il log nella console di 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
Questo comando deve restituire l'elemento creato (con un identificatore):
{"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"}
Creare una seconda attività usando il comando cURL seguente:
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
Recuperare quindi i dati usando una nuova richiesta cURL:
curl http://127.0.0.1:8080/api/todos
Questo comando restituisce l'elenco delle attività, inclusa quella appena creata:
[
{"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}
]
Testare l'applicazione
Per testare l'applicazione, è possibile usare la classe TodoResourceTest
esistente. Deve testare l'endpoint REST. Per testare l'endpoint, usa RESTAssured. Sostituire il codice nella classe TodoResourceTest
con il codice seguente:
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);
}
}
Per testare l'applicazione, è anche necessario che Docker Desktop sia in esecuzione, perché Quarkus rileva di aver bisogno del database PostgreSQL per i test. Testare l'applicazione usando questo comando:
./mvnw clean test # On Mac or Linux
mvnw.cmd clean test # On Windows
Verrà visualizzato un output simile a questo:
[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] ------------------------------------------------------------------------