Quarkus の Panache-Mongo で簡単 CosmosDB 入門
今回は Azure の分散マルチモデルDBの CosmosDB をDBとして、いつもの Quarkus + Panache で簡単 REST API を構築してみたいとおもいます。
CosmosDB は"マルチモデル"なので様々なインタフェースを経由してアクセスが可能です。(インスタンス作成時にどのモデルを使用するか選択があり、作成後はそのモデルでのアクセスとなるので、一つのインスタンスに対して同時に複数のモデルのAPIからアクセスできるわけではないです)。
これまでやってこなかったPanacheのMongoDB対応の機能を使ってみましょう。
1. CosmosDB のインスタンス作成
まずは Azure のポータルからCosmosDBのリソースを作成しましょう。
リストの中から "CosmosDB" を選択します。なければ cosmos
などで検索です。
見つからなければ"検索" というのがどうも、ねぇ。。。
続いて CosmosDB のリソース作成時にAPIを"MongoDB"にするのを忘れないでください。
2. Quarkus プロジェクトの作成
まずは以下の公式ガイドを参考に、MongoDB+Panache のQuarkusプロジェクトを作成いたします。
以下の maven コマンドを叩きます。
$ mvn io.quarkus:quarkus-maven-plugin:1.0.0.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=mongodb-panache-quickstart \
-DclassName="org.acme.mongodb.panache.FruitResource" \
-Dpath="/fruits" \
-Dextensions="resteasy-jsonb,mongodb-panache"
...
$ cd mongodb-panache-quickstart
いつもの通り・・・って!!! quarkus-maven-plugin:1.0.0.Final
ですよ!ついに正式版きましたー!!!(今、githubのリポジトリ確認したら 1.0.1.Final出てましたが・・・)
続いて MongoDB の接続先として先ほど控えておいた CosmosDB の接続文字列を application.properties
に追記します。
# configure the MongoDB client for a replica set of two nodes
quarkus.mongodb.connection-string = mongodb://.............
# mandatory if you don't specify the name of the database using @MongoEntity
quarkus.mongodb.database = person
3. Entityクラスの作成
いつものように Person
エンティティを作成します。今回は PanacheMongoEntity
をベースクラスにします。
またクラスのアノテーションで保存先のコレクションを"ThePerson"としています。
package org.acme.mongodb.panache.model;
import java.time.LocalDate;
import org.bson.codecs.pojo.annotations.BsonProperty;
import io.quarkus.mongodb.panache.MongoEntity;
import io.quarkus.mongodb.panache.PanacheMongoEntity;
@MongoEntity(collection="ThePerson")
public class Person extends PanacheMongoEntity {
public enum Status {
Alive, DECEASED
}
public String name;
// will be persisted as a 'birth' field in MongoDB
@BsonProperty("birth")
public LocalDate birthDate;
public Status status;
}
@BsonProperty
アノテーションによりbirthDate
フィールドのBSONでのキーをbirth
としています。
続いて REST API の実装に参りましょう。
4. REST API の実装
以下のようにシンプルに POST
とGET
だけのAPIを作成いたします。
package org.acme.mongodb.panache;
import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.acme.mongodb.panache.model.Person;
import org.bson.types.ObjectId;
@Path("/person")
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
@POST
public Person create(Person person) {
person.persist();
return person;
}
@GET
@Path("/{id}")
public Person get(@PathParam("id") ObjectId id) {
return Person.findById(id);
}
}
ほとんどHibernateの時と同じですが、一点だけ注意があります。PanacheMongoEntity
はIDをorg.bson.types.ObjectId
型としています。
よって findById
に渡すObjectもObjectId
としてください。
あとはRest EasyとPanacheが宜しくやってくれます。
ちなみに、現時点での mongodb-panache
プラグインはトランザクションは未サポートの模様です。
5. 開発サーバーでの確認
実装が完了したところで一旦、開発サーバーで動作確認をしてみましょう。
以下のコマンドで開発サーバーを起動します。
$ mvn quarkus:dev
起動が完了したところで、まずはターミナルからcurl
コマンドにてJSONデータをPOSTしてみます。
$ curl -H 'Content-Type:application/json' -d '{"name":"Alice","birth":"2010-10-11","status":"Alive"}' http://localhost:8080/person
{"id":"5ddfb90c682fc42ef21e666f","name":"Alice","status":"Alive"}
はい、id
にランダム?な文字列が入ったレコードが返ってきました。これはちゃんと登録されていそうですね。
Azureポータルの管理画面、データエクスプローラーを開いてみましょう。
無事に5ddfb90c682fc42ef21e666f
のObjectId
のデータが確認できました!ちゃんと入っているようです!
ブラウザからも http://localhost:8080/person/5ddfb90c682fc42ef21e666f
を叩いてみましょう!
はい、JSONなので飾り気なしですが、5ddfb90c682fc42ef21e666f
、取れましたね!
6. ネイティブ化
ネイティブ化にも挑戦してみます!
CosmosDB への接続には SSL が必須ですので以下のページを参考に、SSL対応版ネイティブビルドを行います。
と言っても Dockerfile
を以下のようにするだけです。
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:19.2.1 AS build
RUN mkdir -p /tmp/ssl-libs/lib \
&& cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs \
&& cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-libs/lib/
COPY mongodb-panache-quickstart/src /usr/src/app/src
COPY mongodb-panache-quickstart/pom.xml /usr/src/app
USER root
RUN chown -R quarkus /usr/src/app
USER quarkus
RUN mvn -f /usr/src/app/pom.xml -Pnative -Dmaven.test.skip=true clean package
## Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=build /usr/src/app/target/*-runner /work/application
COPY --from=build /tmp/ssl-libs/ /work/
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djava.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/work/cacerts"]
ページのサンプルそのままですが /tmp/ssl-libs
に graalvm
から cacerts
と sunec
のスタティックライブラリをコピーして、実行用イメージにてそれらを参照するように追加を行いました。
続いて、これを参照する docker-compose.yml
を作成します。
version : "3"
services:
quarkus:
build:
context: .
ports:
- 8080:8080
で、ビルドを行います。
$ docker-compose build
7. ネイティブの動作確認
早速、起動してみましょう。
$ docker-compose up -d
で、いつもの通りcurl
でPOST します。
$ $ curl -H 'Content-Type:application/json' -d '{"name":"Alice","birth":"2010-10-11","status":"Alive"}' http://localhost:8080/person
{"id":"5ddfc8c96b679d01d9bc40c0","name":"Alice","status":"Alive"}
先ほどと違うIDでちゃんと返ってきました!
ブラウザで http://localhost:8080/person/5ddfc8c96b679d01d9bc40c0
を叩いてみます。
CosmosDBのデータエクスプローラーからも確認してみます。
2つ目のドキュメントが生成されていることが確認できましたね!
お疲れ様でした!
まとめ
駆け足でしたが Panache から MongoDB Clientを経由して CosmosDB にデータの読み書きができることが確認できました。
また、ネイティブビルドしたバイナリからでもちゃんと CosmosDB にSSL接続できることが確認できました!
早々にAzureContainerでもデプロイしてみたいですが本日はここまでといたします。
今回の成果物は以下のリポジトリにあげました。ご参考にどうぞ。