MicroProfile でクラウドネイティブアプリケーション開発 2 (*再投稿)

記事
IT・テクノロジー

* 画面キャプチャの貼り付けに失敗していたため再投稿しています。


学習の続き(RESTful ウェブサービスのサンプル)

この記事では、前回と同様に Open Liberty のスターターアプリケーションを元にしてサンプルとなる RESTful ウェブサービスを作成する。
今回の内容は MicroProfile というより Jakarta EE RESTful ウェブサービスの仕様に関するものが中心となる。

まずは前回と同じように、openliberty.io/start/ のページからプロジェクトファイルをダウンロードする。
それぞれの入力値は下の画像の通り。IDE は IntelliJ IDEA 2023.3.2 (Community Edition) を使用している。

1.png


ダウンロードしたZIPファイルを example ディレクトリに展開して、IDE で開く。Java のソースファイル NamesResource.java を追加する。
2.png


下の画像のようにNamesResourceクラスを定義する。(package と import 宣言の部分は画像から除いている。)
(NamesResouce.java)
names_resource0.png

HashMap<Integer, String> タイプの static フィールドである names が、このウェブリソースが保持するデータとなっている。 static としているのは、NameResource クラスのインスタンス間でこのデータを共有するため。(リソースクラスのインスタンスはそれぞれの HTTP リクエストに対して生成されることに注意)

RestApplication.java では ApplicationPath アノテーションの値を "/" に設定している。
(RestApplication.java)
RestApplication.png


アプリケーションの実行方法については前回の記事を参照のこと。

POST メソッドでデータの追加

NameResource クラスの post メソッドによって、 POST リクエストでテキストデータを送信することでデータを追加することが可能になっている。
具体的には names.put(id, name) によって、id と name の値に対応する HashMap<Integer, String> の要素が追加される。

(データの例)
id    name
1     Tanaka
2     Suzuki

curl の実行例
例えば id の値が 1 のデータを追加するには下記のように curl を実行する。(-v オプションを使うとHTTPヘッダーも含めて表示できる)
curl -X POST -H "Content-Type: text/plain" --data "Tanaka" localhost:9080/example/names/1

POST リクエストが送られると post メソッドが実行されるが、そのとき --data で指定している "Takana" 文字列が name パラメータの値となる。 また、 URL の example/names/1 の最後の部分の数字が id の値となる。

URL の値をパラメータとしてソース中で扱うには、次に説明する Path アノテーションと PathParam アノテーションの機能を利用している。

URI テンプレート

NamesResouce クラス定義には上で見るように、Path("name/{id}") のようなアノテーションが付加されている。
Path アノテーションの括弧内に指定する値(URI パステンプレートという)にはパラメータを埋め込むことができる。パラメータは { } で囲むことで指定する。

この例だと、リクエストのURI パスの name/ より後ろのセグメントの文字列がパラメータ id の値となる。

PathParam アノテーションを使うと、パラメータの値をフィールド、またはメソッドパラメータにインジェクトすることができる。(パラメータの値がフィールドやパラメータに代入される)
NamesResouce クラスでは、Integer 型のフィールド id に PathParam("id") アノテーションを付加している。

GET リクエストでデータの取得
localhost:9080/example/names/1 に GET リクエストを送信すると id=1 に対応する文字列データがレスポンスとして返される。

(curl の実行例。-v オプションでHTTP ヘッダも含めて表示している)
curl.png

リソースクラスのメソッドが null を返す場合

指定した id の値に対してデータが存在しない場合は names.get(id) が null を返すので、NamesResouce クラスの get メソッドの返り値も null となる。このような場合には 204 ステータスコードが使われることが仕様で定められている。

試しに id の値 2 に対するデータをリクエストしてみると、204 No Content のレスポンスが返される。(レスポンスのボディは空となっている)
curl2.png

Exception マッピングプロバイダーで例外処理

リソースクラスのメソッドが例外を発生したとき(throw したとき)、その例外に対応するプロバイダーがレスポンス(Response インスタンス)を決めるために使われる。

Exception マッピングプロバイダーは ExceptionMapper<T> インターフェースを実装するクラスとして定義される。クラスがプロバイダーとして登録されるためには Provider アノテーションを使う。

タイプパラメーターの T でマップする対象の例外クラスを指定する。指定したクラスとそのサブクラスの例外がこのプロバイダーにマップされる。
マッピングのルールとして、発生した例外のクラスに対して最も近い親クラスのプロバイダーが選択される。
複数の候補がある場合は Priority アノテーションで指定できる優先度の値(小さい方が優先度が高い)に従ってマップ先が決まる。優先度が等しい場合の選択は仕様では定められていない。(アプリケーションサーバー等の実装による?)

この記事のアプリケーションでは、指定した id に対するデータがない場合に例外を発生させるようにするとともに、対応するプロバイダークラスを定義してこの例外発生時のレスポンスを変更する。例外のクラスは NotFoundException を使用する。

NamesResource クラスの get メソッド定義を下の画像のように変更する。
resourse-mod.png

これによって、id の値に対応するデータが names に含まれない場合、NotFoundException が発生する。

NotFoundExceptionMapper.java ファイルを追加し、下の画像のようにプロバイダークラスを定義する。toResponse メソッドをオーバーライドして定義することで、この例外が発生した場合のレスポンスを定義できる。
NotFound.png

ステータスコードを404に設定し、レスポンスボディには例外発生時のメッセージを含めるようにする。

id=2 のデータをリクエストすると 404 Not Found が返されるようになる。
404.png


デフォルトのException マッピングプロバイダー
ExceptionMapper<Throwable> を実装するプロバイダーがデフォルトで存在するので、プロバイダーを一つも定義していない場合はこのプロバイダーが使われる。

レスポンスステータスは 500 に設定されるが WebApplicationException の場合はその例外に埋め込まれた Response が使われる。ステータスコードもこの Response インスタンスの設定値を使う。

次回以降の記事では、テキストデータではなくJSON データを扱う方法などを学習する予定。

参考資料:
"Jakarta RESTful Web Services 3.1" の仕様書 (URL: jakarta.ee/specifications/restful-ws/3.1)

コメント: 記事内の情報は著者が個人的に調べた範囲で理解しているものです。必要に応じて訂正する場合があります。記事中に含まれるURL はプロトコルを含めると禁止ワードに引っ掛かるので省いています。

著者・投稿者: ENARTS05
編集履歴:
2024/1/19 作成
2024/2/17 画像の貼り付けをやり直し
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す