- はじめに
- プロジェクトの作成
- 開発モードの起動
- Entity を作成する
- JAX-RS リソースを作成する
- Continuous Testing
- CRUD メソッドの追加
- OpenAPI と Swagger UI
- まとめ
はじめに
今回は、Quarkus CLI を使ったアプリケーション作成の流れについて説明します。
Panache を使った簡単な CRUD アプリケーションを例に取り上げましょう。
Quarkus CLI の詳細については以下を参照してください。
プロジェクトの作成
Quarkus CLI にてプロジェクトを作成します。
$ quarkus create app --gradle --java -x=quarkus-resteasy-jackson,quarkus-hibernate-orm-panache,quarkus-jdbc-h2 com.mammb:quarkus-panache:0.1.0
以下の Extension を追加しました。
- io.quarkus:quarkus-resteasy-jackson
- hibernate-orm-panache
- quarkus-jdbc-h2
プロジェクトは以下のように作成されます。
----------- selected extensions: - io.quarkus:quarkus-hibernate-orm-panache - io.quarkus:quarkus-jdbc-h2 - io.quarkus:quarkus-resteasy-jackson applying codestarts... 📚 java 🔨 gradle 📦 quarkus 📝 config-properties 🔧 dockerfiles 🔧 gradle-wrapper 🚀 resteasy-codestart ----------- [SUCCESS] ✅ quarkus project has been successfully generated in: --> /<path>/quarkus-panache ----------- Navigate into this directory and get started: quarkus dev
開発モードの起動
プロジェクトが作成されたら開発モードで起動します。
$ quarkus dev
開発モードで d
を入力すれば Dev UI が起動します。
導入した Extension が表示されます。
Configuration にある Config Editor からデータベースの自動生成の項目の設定を入れておきましょう。
quarkus.hibernate-orm.database.generation
を検索し、drop-and-create
に設定します。
✅ ボタンで反映すれば、src/main/resources/application.properties
に編集内容が反映されます。これにより、データベースのテーブルがアプリケーション起動時にドロップされて再作成されるようになります。
開発モードではライブコーディングが有効になっているため、後はソースを書いていくだけで、即座に変更内容を確認することができます。
Entity を作成する
Panache による Entity を作成します。今回は Repository は利用せず、PanacheEntity を継承して Entity を作成します。
単純な Person をsrc/main/java/com/mammb/Person.java
に作成します。
package com.mammb; import javax.persistence.Column; import javax.persistence.Entity; import java.time.LocalDate; import io.quarkus.hibernate.orm.panache.PanacheEntity; @Entity public class Person extends PanacheEntity { @Column(length = 120, unique = true) public String name; public LocalDate birth; }
Panache では、属性は public
で定義して getter/setter は書きません。コンパイル時に自動生成されます。
getter/setter を明示的に定義すれば そちらが使用されます。
PanacheEntity
には Entity 操作のメソッドが定義されているため、Entity に関連する準備はこれで完了です。
JAX-RS リソースを作成する
JAX-RS リソース をsrc/main/java/com/mammb/PersonResource.java
に作成します。
package com.mammb; import javax.transaction.Transactional; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.List; import io.quarkus.panache.common.Sort; @Path("/persons") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class PersonResource { @GET public List<Person> get() { return Person.listAll(Sort.by("name")); } @POST @Transactional public Response create(Person person) { if (person.id != null) { throw new WebApplicationException("Id was invalidly set on request.", 422); } person.persist(); return Response.ok(person).status(201).build(); } }
一覧取得と新規登録用のメソッドを追加しました。
Person.listAll()
でデータベースから select、person.persist()
でデータベースへの insert 操作となります。
この時点で、w
を押せばブラウザが起動してアプリケーションを確認できます。
Continuous Testing
Quarkus 2.0 で導入された Continuous Testing でテストはコードを変更する毎に自動で実行されます。コンソール(または Dev UI)で r
を押すことで実行モードを切り替えることができます。
PersonResource
のテストをsrc/test/java/com/mammb/PersonResourceTest.java
に作成しましょう。
package com.mammb; import javax.ws.rs.core.MediaType; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; @QuarkusTest public class PersonResourceTest { @Test public void testPersonEndpoint() { given() .body("{'name':'Quarkus','birth':'2000-01-01'}".replace('\'', '"')) .header("Content-Type", MediaType.APPLICATION_JSON) .when().post("/persons") .then() .statusCode(201) .body("name", is("Quarkus")); given() .when().get("/persons") .then() .statusCode(200) .body(containsString("Quarkus")); } }
コードを変更すると、その場で関連するテストが自動実行され、もし失敗するテストがあれば、以下のようにテストの失敗がレポートされます。
コードを修正すれば再びテストがされます。
Continuous Testing では、このようにコード変更に応じて継続的にテストを実行することができます。
CRUD メソッドの追加
PersonResource
に、その他の CRUD メソッドを追加しましょう。
public class PersonResource { // ... @GET @Path("{id}") public Person getSingle(@PathParam Long id) { Person entity = Person.findById(id); if (entity == null) { throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); } return entity; } @PUT @Path("{id}") @Transactional public Person update(@PathParam Long id, Person person) { if (person.name == null) { throw new WebApplicationException("Fruit Name was not set on request.", 422); } Person entity = Person.findById(id); if (entity == null) { throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); } entity.name = person.name; entity.birth = person.birth; return entity; } @DELETE @Path("{id}") @Transactional public Response delete(@PathParam Long id) { Person entity = Person.findById(id); if (entity == null) { throw new WebApplicationException("Fruit with id of " + id + " does not exist.", 404); } entity.delete(); return Response.status(204).build(); } }
合わせてテストも追加しておきましょう。
@QuarkusTest public class PersonResourceTest { @Test public void testPersonEndpoint() { Integer id = given() .header("Content-Type", MediaType.APPLICATION_JSON) .body("{'name':'Quarkus','birth':'2000-01-01'}".replace('\'', '"')) .when().post("/persons") .then() .statusCode(201) .body("name", is("Quarkus")) .extract().path("id"); given() .when().get("/persons/" + id) .then() .statusCode(200) .body("name", is("Quarkus"), "birth", is("2000-01-01")); given() .header("Content-Type", MediaType.APPLICATION_JSON) .body("{'name':'Quarkus2','birth':'2000-01-01'}".replace('\'', '"')) .when().put("/persons/" + id) .then() .statusCode(200) .body("name", is("Quarkus2")); given() .when().delete("/persons/" + id) .then() .statusCode(204); given() .when().get("/persons") .then() .statusCode(200) .body(is("[]")); } }
アプリケーションは一先ずこれで完了です。
OpenAPI と Swagger UI
作成したエンドポイントの OpenAPI Specification を作成します。
開発コンソールを q
で一旦抜けて、OpenAPI の Extension を追加します。
$ quarkus ext add quarkus-smallrye-openapi
Extension が追加できたら quarkus dev
で再度開発モードで起動します。
d
で Dev UI を見ると、SmallRye OpenAPI として Extension が追加されたことが確認できます。
openapi
のリンクを押せば、OpenAPI Specification ファイルがダウンロードできます。
--- openapi: 3.0.3 info: title: quarkus-panache API version: 0.1.0 paths: /hello: get: responses: "200": description: OK content: text/plain: schema: type: string /persons: get: responses: "200": description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/Person' post: requestBody: content: application/json: schema: $ref: '#/components/schemas/Person' responses: "200": description: OK /persons/{id}: get: parameters: - name: id in: path required: true schema: format: int64 type: integer responses: "200": description: OK content: application/json: schema: $ref: '#/components/schemas/Person' put: parameters: - name: id in: path required: true schema: format: int64 type: integer requestBody: content: application/json: schema: $ref: '#/components/schemas/Person' responses: "200": description: OK content: application/json: schema: $ref: '#/components/schemas/Person' delete: parameters: - name: id in: path required: true schema: format: int64 type: integer responses: "200": description: OK components: schemas: Person: type: object properties: id: format: int64 type: integer birth: format: date type: string name: type: string
APIタイトル やバージョンなどの API情報は、MicroProfile OpenAPI アノテーションで Application クラスに定義することができる他、application.properties
に記載することもできます(ここでは省略します)。
Swagger UI は同様に SmallRye OpenAPI のリンクから開くことができます。
API 仕様の確認や、API の実行を簡単に行うことができます。
まとめ
Quarkus による簡単な CRUD 操作を行うアプリケーション作成の流れについて説明しました。
Quarkus CLI コマンドと Dev Services だけを操作していれば良いため、開発作業の立ち上げがとても簡素になりますので、試してみると良いと思います。