Exercício - Criar um aplicativo Quarkus

Concluído

Nesta unidade, você cria um aplicativo Quarkus básico. Você usa o Maven para inicializar o aplicativo e um ambiente de desenvolvimento integrado (IDE) de sua escolha para editar o código. Use um terminal de sua escolha para executar o código. Você usa o Docker para iniciar um banco de dados PostgreSQL local para que possa executar e testar o aplicativo localmente.

Gerar o aplicativo Quarkus usando o Maven

Há várias maneiras de gerar uma estrutura de projeto Quarkus. Você pode usar a interface web do Quarkus , um plug-in IDE ou o plug-in do Quarkus Maven. Vamos usar o plugin Maven para gerar a estrutura do projeto.

Você gera seu aplicativo com várias dependências:

  • A dependência resteasy para expor um endpoint REST
  • A jackson dependência de serializar e desserializar JSON
  • A dependência hibernate para interagir com a base de dados
  • A dependência postgresql para se conectar ao banco de dados PostgreSQL
  • A dependência docker para criar uma imagem do Docker

Você não precisa especificar as dependências do Azure porque primeiro executa seu aplicativo localmente e, em seguida, implanta uma versão em contêiner dele nos Aplicativos de Contêiner do Azure.

Em um prompt de comando, gere o aplicativo to-do:

mvn -U io.quarkus:quarkus-maven-plugin:3.19.0:create \
    -DplatformVersion=3.18.4 \
    -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"

Este comando cria um novo projeto Quarkus. Ele gera uma estrutura de diretórios Maven (src/main/java para código-fonte e src/test/java para testes). Ele cria algumas classes Java, alguns testes e alguns Dockerfiles. Ele também gera um arquivo pom.xml com todas as dependências necessárias (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>

Observação

Todas as dependências no ficheiro pom.xml são definidas na BOM (Bill of Materials) do Quarkus io.quarkus.platform:quarkus-bom.

Codifique o aplicativo

Em seguida, renomeie a classe MyEntity.java gerada para Todo.java (localizada na mesma pasta que o arquivo TodoResource.java ). Substitua o código existente pelo seguinte código Java. Ele usa Java Persistence API (pacotejakarta.persistence.*) para armazenar e recuperar dados do seu servidor PostgreSQL. Ele também usa Hibernate ORM com Panache (herdando de io.quarkus.hibernate.orm.panache.PanacheEntity) para simplificar a camada de persistência.

Você usa uma entidade JPA (@Entity) para mapear o objeto Java Todo diretamente para a tabela de Todo PostgreSQL. Em seguida, o ponto de extremidade REST TodoResource cria uma nova classe de entidade Todo e a persiste. Essa classe é um modelo de domínio mapeado na tabela Todo. A tabela é criada automaticamente pela JPA.

Estender PanacheEntity fornece uma série de métodos genéricos de criação, leitura, atualização e exclusão (CRUD) para seu tipo. Assim, você pode fazer coisas como salvar e excluir objetos Todo em apenas uma linha de código Java.

Adicione o seguinte código à entidade 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 +
                '}';
    }
}

Para gerenciar essa classe, atualize o TodoResource para que ele possa publicar interfaces REST para armazenar e recuperar dados usando HTTP. Abra a classe TodoResource e substitua o código pelo seguinte:

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();
    }
}

Execute o aplicativo

Quando você executa o aplicativo no modo de desenvolvimento, o Docker precisa estar em execução. Isso porque o Quarkus deteta que você precisa de um banco de dados PostgreSQL (por causa da dependência quarkus-jdbc-postgresql do PostgreSQL declarada no arquivo pom.xml ), baixa a imagem do Docker PostgreSQL e inicia um contêiner com o banco de dados. Em seguida, ele cria automaticamente a tabela Todo no banco de dados.

Verifique se o Docker está sendo executado localmente em sua máquina e execute o aplicativo to-do usando este comando:

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

O aplicativo Quarkus deve iniciar e se conectar ao seu banco de dados. Você deve ver a seguinte saída:

2025-02-28 08:38:33,418 INFO  [io.qua.dat.dep.dev.DevServicesDatasourceProcessor] (build-28) Dev Services for default datasource (postgresql) started - container ID is ce37977203b0
2025-02-28 08:38:33,421 INFO  [io.qua.hib.orm.dep.dev.HibernateOrmDevServicesProcessor] (build-6) Setting quarkus.hibernate-orm.database.generation=drop-and-create to initialize Dev Services managed database
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2025-02-28 08:38:35,278 INFO  [io.quarkus] (Quarkus Main Thread) todo 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.18.4) started in 5.367s. Listening on: http://localhost:8080

2025-02-28 08:38:35,280 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2025-02-28 08:38:35,280 INFO  [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 [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>

Para testar o aplicativo, você pode usar cURL.

Em um terminal separado, crie um novo item de to-do no banco de dados com o seguinte comando. Você deve ver o log no console do 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

Este comando deve retornar o item criado (com um identificador):

{"id":1,"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done":true,"createdAt":"2025-02-26T07:27:30.093447Z"}

Crie um segundo to-do usando o seguinte comando cURL:

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

Em seguida, recupere os dados usando uma nova solicitação cURL:

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

Este comando retorna a lista de to-do itens, incluindo os itens que você criou:

[ 
  {"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}
]

Testar a aplicação

Para testar o aplicativo, você pode usar a classe TodoResourceTest existente. É necessário testar o endpoint REST. Para testar o ponto de extremidade, ele usa RESTAssured. Substitua o código na classe TodoResourceTest com o seguinte código:

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);
    }
}

Quando você testa o aplicativo, o Docker Desktop precisa estar em execução porque o Quarkus deteta que ele precisa do banco de dados PostgreSQL para teste. Teste o aplicativo usando este comando:

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

Você deve ver uma saída semelhante a esta:

[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] ------------------------------------------------------------------------