Alıştırma - Quarkus uygulaması oluşturma

Tamamlandı

Bu ünitede temel bir Quarkus uygulaması oluşturacaksınız. Maven kullanarak uygulamayı ve kodu düzenlemek için tercih ettiğiniz tümleşik geliştirme ortamını (IDE) önyüklersiniz. Kodu çalıştırmak için önkoşullarda yapılandırılan Bash ortamını kullanın. Docker'ı kullanarak yerel bir PostgreSQL veritabanı başlatırsınız, böylece uygulamayı yerel olarak çalıştırabilir ve test edebilirsiniz.

Maven kullanarak Quarkus uygulamasını oluşturma

Quarkus proje yapısı oluşturmanın birkaç yolu vardır. Quarkus web arabirimini, IDE eklentisini veya Quarkus Maven eklentisini kullanabilirsiniz. Proje yapısını oluşturmak için Maven eklentisini kullanalım.

Uygulamanızı çeşitli bağımlılıklarla oluşturursunuz:

  • resteasy bağımlılığı ile bir REST uç noktasını kullanıma sunma
  • JSON'u serileştirmek ve seri durumdan çıkarmak için jackson bağımlılığı
  • Veritabanıyla etkileşime geçmek için hibernate bağımlılığı
  • PostgreSQL veritabanına bağlanmak için postgresql bağımlılığı
  • Docker görüntüsü oluşturmak için quarkus-container-image-docker bağımlılığı

Önce uygulamanızı yerel olarak çalıştırıp ardından azure containerized sürümünü Azure Container Apps'e dağıttığınızdan Azure bağımlılıkları belirtmeniz gerekmez.

Not

Bu modüldeki komutlar Bash söz dizimini kullanır. Bunları değiştirmeden PowerShell'e veya Windows Komut İstemi'ne yapıştırmayın. Windows'ta, yapılandırılan WSL dağıtımında Bash komutlarını çalıştırın. Uygulama çalışırken HTTP istekleri için başka bir yerel Bash terminali kullanın.

Projeyi oluşturmadan önce Bash ortamınızın Java 17 ve Maven 3.9.9 kullanıp kullanmadığını denetleyin:

java -version
mvn --version

İlk oluşturucu komutu yüklü Maven'inizi kullanır. Projenin Maven sarmalayıcısı daha sonra oluşturulur, bu nedenle bu önkoşulu değiştirmez. Devam etmeden önce gerekli Java ve Maven sürümlerini seçin.

Projeyi oluşturmak istediğiniz dizinde to-do uygulamasını oluşturmayı başlatın:

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, io.quarkus:quarkus-container-image-docker"

Bu komut, todo adlı dizinde yeni bir Quarkus projesi oluşturur. Bir Maven dizin yapısı oluşturur (kaynak kodu içinsrc/main/java ve testler için src/test/java). Bazı Java sınıfları, bazı testler ve bazı Dockerfile'lar oluşturur. Ayrıca tüm gerekli bağımlılıkları (Hazırda Beklet, RESTEasy, Jackson, PostgreSQL ve Docker) içeren bir pom.xml dosyası oluşturur:

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

Not

pom.xml dosyasındaki tüm bağımlılıklar Quarkus BOM(ürün reçetesi) io.quarkus.platform:quarkus-bomiçinde tanımlanır.

Uygulamayı kodlayın

Ardından, oluşturulan MyEntity.java sınıfını Todo.java olarak yeniden adlandırın ( TodoResource.java dosyasıyla aynı klasörde bulunur). Mevcut kodu aşağıdaki Java koduyla değiştirin. PostgreSQL sunucunuzdan veri depolamak ve almak için Java Kalıcılık API'sini (jakarta.persistence.* paketi) kullanır. Ayrıca kalıcılık katmanını basitleştirmek için, 'den devralarak Panache io.quarkus.hibernate.orm.panache.PanacheEntity Hibernate ORM'yi kullanır.

Java @Entity nesnesini doğrudan PostgreSQL Todo tablosuna eşlemek için jpa varlığı (Todo) kullanırsınız. TodoResource REST uç noktası daha sonra yeni bir Todo varlık sınıfı oluşturur ve bunu kalıcı hale alır. Bu sınıf, Todo tablosuna eşlenen bir etki alanı modelidir. Tablo JPA tarafından otomatik olarak oluşturulur.

PanacheEntity genişletmek, türünüz için bir dizi genel oluşturma, okuma, güncelleştirme ve silme (CRUD) yöntemi sağlar. Böylece, Todo nesneleri tek bir Java kodu satırında kaydetme ve silme gibi işlemler yapabilirsiniz.

Todo varlığına aşağıdaki kodu ekleyin:

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 +
                '}';
    }
}

Bu sınıfı yönetmek için TodoResource güncelleştirerek HTTP kullanarak verileri depolamak ve almak için REST arabirimleri yayımlayabilmesini sağlayın. TodoResource sınıfını açın ve kodu aşağıdakilerle değiştirin:

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.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
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();
    }

    @GET
    @Path("/{id}")
    public Todo getTodo(@PathParam("id") Long id) {
        Todo todo = id == null ? null : Todo.findById(id);
        if (todo == null) {
            throw new NotFoundException();
        }
        return todo;
    }
}

POST yöntemi, yeni öğenin URI'sini Location üst bilgisinde döndürür. ÖĞE GET yöntemi bu URI'yi işler ve öğe bulunamazsa HTTP 404 döndürür. Null guard ayrıca RESTEasy'nin null tanımlayıcıya dönüştürdüğü yol değerlerini Panache'ye null geçirmeden işler.

Uygulamayı çalıştırma

Uygulamayı geliştirme modunda çalıştırdığınızda Docker'ın çalışıyor olması gerekir. Bunun nedeni Quarkus'un postgreSQL veritabanına ihtiyacınız olduğunu algılaması (quarkus-jdbc-postgresql dosyasında bildirilen PostgreSQL bağımlılığı nedeniyle), PostgreSQL Docker görüntüsünü indirmesi ve veritabanıyla bir kapsayıcı başlatmasıdır. Ardından veritabanında Todo tablosunu otomatik olarak oluşturur.

Not

Sabitlenmiş Quarkus 3.18.4 platformu, Java Docker istemcisi varsayılan olarak API 1.32 olan Testcontainers 1.20.4'ü kullanır. Docker Engine 29.x artık bu API sürümünü varsayılan olarak kabul etmemektedir. Engine 29.x kullanıyorsanız docker version komutunu çalıştırın ve sunucunun desteklenen API aralığının 1.44'ü içerdiğini onaylayın. Yalnızca öyleyse, Quarkus'u veya testleri başlatmadan önce bu Bash kabuğunda aşağıdaki komutu çalıştırın:

export JDK_JAVA_OPTIONS="${JDK_JAVA_OPTIONS:+$JDK_JAVA_OPTIONS }-Dapi.version=1.44"

Bu ayarı test ve sonraki paket komutları için aynı kabukta tutun. JDK_JAVA_OPTIONS, sabitlenmiş Quarkus sürümlerini değiştirmeden Java başlatıcı işlemlerine Java sistem özelliği sağlar. DOCKER_API_VERSION tek başına, Java Docker istemcisinin bu sürümünü yapılandırmaz. Desteklenen aralığı API 1.44'ü kapsamayan bir sunucuda API 1.44'ü zorlamayın; bunun yerine ayrı olarak doğrulanmış uyumlu bir Docker ve istemci yapılandırması kullanın.

Docker'ın çalıştığından ve yapılandırılan Bash ortamınızdan erişilebilir olduğundan emin olun. Projeyi oluşturduğunuz terminalde todo dizinine girin ve uygulamayı başlatın:

cd todo
./mvnw quarkus:dev

Sonraki tüm Maven komutlarını bu oluşturulan todo dizininden çalıştırın.

Quarkus uygulamasının başlatılması ve veritabanınıza bağlanması gerekir. Aşağıdaki çıkışı görmeniz gerekir:

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>

Uygulamayı test etmek için cURL kullanabilirsiniz.

İkinci bir yerel Bash terminalinde, aşağıdaki komutu kullanarak veritabanında yeni bir to-do öğesi oluşturun. Günlüğü Quarkus konsolunda görmeniz gerekir:

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

Bu komut, oluşturulan öğeyi döndürmelidir (tanımlayıcı ile):

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

Aşağıdaki cURL komutunu kullanarak ikinci bir to-do oluşturun:

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

Ardından, yeni bir cURL isteği kullanarak verileri alın:

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

Bu komut, oluşturduğunuz öğeler de dahil olmak üzere to-do öğelerinin listesini döndürür. Her öğe ayrıca createdAt içerir; aşağıdaki örnek bu zaman damgalarını kısa olması için atlar:

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

Uygulamayı test edin

HTTP denetimlerinden sonra Quarkus çalıştıran terminale dönün ve geliştirme modunu durdurmak için Ctrl+ tuşuna basın. Bu Bash kabuğunu açık tutun ve test komutu için todo dizininde kalın.

Uygulamayı test etmek için mevcut TodoResourceTest sınıfını kullanabilirsiniz. REST uç noktasını test etmesi gerekir. Uç noktayı test etmek için RESTAssured kullanır. Testler koleksiyon denetimini korur, POST tarafından döndürülen Location öğesini izler ve eksik ve geçersiz öğe tanımlayıcılarını denetler. TodoResourceTest sınıfındaki kodu aşağıdaki kodla değiştirin:

package com.example.demo;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.response.Response;
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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
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;

        Response created = given().body(todo)
                .header(CONTENT_TYPE, APPLICATION_JSON)
                .when().post("/api/todos")
                .then()
                .statusCode(201)
                .extract().response();

        String location = created.getHeader("Location");
        assertNotNull(location);
        long createdId = created.jsonPath().getLong("id");

        Response retrieved = given()
                .when().get(location)
                .then()
                .statusCode(200)
                .extract().response();

        assertEquals(createdId, retrieved.jsonPath().getLong("id"));
        assertEquals(todo.description, retrieved.jsonPath().getString("description"));
    }

    @Test
    void shouldReturnNotFoundForMissingTodo() {
        given()
                .when().get("/api/todos/-1")
                .then().statusCode(404);
    }

    @Test
    void shouldRejectInvalidTodoIds() {
        given()
                .when().get("/api/todos/not-a-number")
                .then().statusCode(404);

        given().urlEncodingEnabled(false)
                .when().get("/api/todos/%20")
                .then().statusCode(404);
    }
}

Oluşturma testi POST yanıtından oluşturulan tanımlayıcıyı okur ve her iki tanımlayıcıyı da long değerleri olarak karşılaştırır. Geçersiz tanımlayıcı testi, isteğin kasıtlı olarak kodlanmış boşluğu içermesi için %20 için otomatik URL kodlamasını devre dışı bırakır.

Uygulamayı test ettiğinizde, Quarkus test için ayrı bir PostgreSQL Geliştirme Hizmeti başlattığından Docker'ın çalışıyor ve aynı Bash ortamından erişilebilir olması gerekir. Quarkus'u durdurduğunuz terminalde şu komutu kullanarak uygulamayı test edin:

./mvnw clean test

Şuna benzer bir çıktı görmelisiniz:

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

Veritabanı alıştırması için bu Bash kabuğunu açık tutun. Orada AZ_POSTGRES_PASSWORD, AZ_POSTGRES_USERNAME ve AZ_POSTGRES_JDBC_URL ayarlayacak, ardından Quarkus'u o kabuktan yeniden başlatacaksınız. Sonraki ve dağıtım adımlarından önce, uzaktan geliştirme işlemini ./mvnw clean package+ ile durdurun. Değişkenleri koruyun ve birimler arasında resource-name ve parola kurulumunu tekrar etmeyin.

Bir işlem başlatıldığında ortamını devralır. Ortam değişkenlerini başka bir terminalde dışa aktarmak, zaten çalışan bir Quarkus işlemini güncelleştirmez. application.properties öğesini düzenlemek ve canlı yeniden yüklemeye güvenmek, Azure'a geçiş için yeterli değildir; değişkenleri ayarladığınız kabuktan uygulamayı yeniden başlatın.