2023年5月11日木曜日

OpenAPIより作成したRESTデータ・ソースを使う

 先日の記事で作成したRESTデータ・ソースをアプリケーションで使ってみます。RESTデータ・ソースはoracle.example.hrとして作成済みとします。


RESTデータ・ソースに含まれている操作の内、データベース・アクションに紐づいている行のフェッチ(GET empinfo/)、単一行のフェッチ(GET employees/{id})、行の更新(PUT employees/{id})の3つの操作を使用します。

上記の3つの操作ですが、適切に使用するために設定の修正を行います


対話モード・レポートとフォームの作成


RESTデータ・ソースoracle.example.hrをソースとした対話モード・レポートとフォームのページを作成します。

ページの作成を実行します。

対話モード・レポートを選択します。

対話モード・レポートのページ名前従業員一覧ページ・モード標準とします。フォーム・ページを含めるオンにし、フォーム・ページ名従業員編集とします。フォーム・ページ・モードドロワーとします。

データ・ソースRESTデータ・ソースを選択し、RESTデータ・ソースとしてoracle.example.hrを選びます。

ナビゲーションはデフォルトまま変更しません。

以上の設定で、へ進みます。


主キー列1としてEMPNO(Number)を選択し、ページの作成を実行します。


対話モード・レポートとフォームのページが作成されます。

作成された対話モード・レポートのページを実行します。

適当な従業員を選んで、編集リンクをクリックします。


対象の従業員を編集するドロワーが開きます。

そのまま変更の適用をクリックします。


エラーが発生し、変更の更新はできません。ページ作成ウィザードは、データを更新するプロセスを適切に生成しないため、データを更新するプロセスを作り直す必要があります。


今までの操作で、実際に発行されたREST APIのURLを確認します。SQLコマンドより以下のSQLを実行します。

select * from apex_webservice_log order by request_date desc;


対話モード・レポートの一覧表示ではGET /empinfo/が呼び出されています。Swagger Editorでの説明は以下です。ページ区切りの設定を行なっていないと全件を取得します。

サンプル・データセットの表EMPは初期状態で14行なので問題ありませんが、何千件、何万件といった行数になると、ページ区切りを実装するか同期化を使って取得結果をローカル・データベースにキャッシュする必要が出てくるでしょう。


編集リンクをクリックしたときもGET /empinfo/が呼び出されています。全件を取得した上で、その中から編集対象の一行を取り出す、という動作になります。

これでは実用上の問題があるため、RESTデータ・ソース操作に含まれる単一行のフェッチ(GET /employees/{id})を呼び出すように変更します。


編集フォーム上で変更の適用をクリックしたときは、GET /employees/が呼び出されています。これは行の更新(PUT employees/{id})の呼び出しに置き換えます。


ページ区切りの設定


使用しているRESTデータ・ソースoracle.example.hrは、Oracle REST Data Servicesで実装しています。Oracle REST Data Servicesでは(ソース・タイプCollection Queryの場合)、ページ区切り(ページネーションとも呼びます)がデフォルトで実装されます。

ORDSのProduct ManagerであるJeff Smithさんの以下の記事を参考にして、RESTデータ・ソースoracle.example.hrにページ区切りを設定します。

How Paging Works in ORDS

RESTデータ・ソースoracle.example.hrを開き、設定のセクションに移動します。

ページ区切りタイプとしてページ・サイズとフェッチ・オフセットを選択します。ページ・サイズURLパラメータlimitページ・サイズ最大とします(適切な値は、対話モード・レポートの1ページで表示される行数よりも大きい値です)。行オフセットURLパラメータoffset行オフセット・タイプとしてスキップする行を選択します。ORDSの場合、offsetは0から始まります。その他の行セレクタとしてhasMoreを指定し、次の値のときのその他の行次と等しいその他の行属性値trueを指定します。

上記はORDSで決められた定義です。RESTサービスの実装が異なれば、上記の設定も異なります。


従業員一覧を再度開き、発行されたREST APIを確認します。すべての行を取り出すために、limitで指定されている6行ごとに3回、REST APIを発行していることが確認できます。

/empinfo/?offset=0&limit=6
/empinfo/?offset=6&limit=6
/empinfo/?offset=12&limit=6

ページごとの行数行にします。


発行されるREST APIは以下の1回に減ります。(limitがページ行数と同じ5だと、追加でREST APIが1回発行されます。その動作を避けるため、limitは表示する行数よりも最低でも1は大きい値にします。)

/empinfo/?offset=0&limit=6

次のページに移動すると、表示される対象の行(以下の例では6行目)からデータを取得します。


発行されるREST APIは以下の1回です。

/empinfo/?offset=5&limit=6


単一行のフェッチの実装



GET /empinfo/を実行し、すべての行をフェッチしてから編集する行を取り出す処理は非効率なので、単一行のフェッチの呼び出しに置き換えます。

GET employees/{id}を呼び出すと、id(列EMPNOの従業員番号)指定で選択された表EMP
の行がJSON形式で返されます。OpenAPI定義から生成されたRESTソース操作では、返却されるJSONドキュメントの処理が行われていません

単一行のフェッチ操作を開いて、返却された値の定義を追加します。


操作パラメータパラメータの追加を実行します。


返却されるJSONドキュメントにどのような属性が含まれるかは、OpenAPIによる定義に含まれています。

パラメータタイプとしてデータ・プロファイル列を選択し、データ・プロファイル列として、最初にCOMMを選択します。

追加後、さらに追加をクリックします。


同じ操作を繰り返しデータ・プロファイル列としてDEPTNOEMPNOENAMEHIREDATEJOBMGRSALを追加します。

操作パラメータをすべて設定した後、変更の適用を実行します。


以上でRESTデータ・ソースの操作の更新は完了です。

ページ・デザイナにて従業員編集の画面を開きます。

レンダリング前にあるプロセス初期化フォーム従業員編集を選択し、ビルド・オプションを使ってコメント・アウトします。削除しても構いません。


代わりになるプロセスを従業員画面の初期化として作成します。

識別タイプとしてAPIの呼び出しを選択します。設定タイプREST Sourceを選択します。Oracle APEX 23.1から、APIの呼び出しでREST Sourceを指定できるようになりました。

RESTソースとしてoracle.example.hr操作としてGET - employees/{id}を選択します。

サーバー側の条件タイプアイテムはNULLではないアイテムとしてP3_EMPNOを指定します。従業員番号が与えられている場合のみ、RESTソースを呼び出しページ・アイテムに値を設定します。


パラメータidを選択し、アイテムとしてP3_EMPNOを割り当てます。


パラメータEMPNOを選択します。出力を無視オンになっています。

EMPNOに対応するページ・アイテムP3_EMPNOは、対話モード・レポートの編集リンクをクリックしたときに引数として渡されるため、このプロセスで初期化する必要はありません。このまま、出力を無視オンにしておきます。


パラメータCOMMを選択します。

出力を無視オフに変更し、アイテムとしてP3_COMMを指定します。


同様にパラメータDEPTNOにページ・アイテムP3_DEPTNOENAMEP3_ENAMEHIREDATEP3_HIREDATEJOBP3_JOBMGRP3_MGRSALP3_SALを設定します。

以上でフォームの初期化プロセスの入れ替えは完了です。

対話モード・レポートのページを実行し、任意の一行の編集画面を開きます。


発行されたREST APIをビューAPEX_WEBSERVICE_LOGから確認すると、以下のようなリクエストが発行されていることが分かります。

GET /employees/7654


行の更新の実装



行の更新を実装します。OpenAPIでは、以下のようなJSONドキュメントをリクエスト本体として送信するように定義されています。
{
  "ename": "string",
  "job": "string",
  "hiredate": "string",
  "mgr": "string",
  "sal": "string",
  "comm": "string",
  "deptno": "string"
}
操作行の更新を開いて、上記のようなREST APIを発行するように設定します。


リクエスト本文テンプレートに何も設定されていません。生成をクリックします。


リクエスト本文テンプレートが生成されます。

操作パラメータ本文との同期というボタンが現れます。これをクリックします。


リクエスト本文にプレースホルダーがない操作パラメータが削除されると警告が表示されます。今回の例ではpayloadが削除されます。

payloadは不要なので、OKをクリックします。


リクエスト本文テンプレートに含まるプレースホルダーが、操作パラメータとして追加されます。


パラメータの追加をクリックし、Content-Typeヘッダーを追加します。

パラメータタイプとしてHTTPヘッダーを選択します。名前Content-Type目的入力デフォルト値としてapplication/jsonを指定します。

静的オンにし、変更不可のパラメータとします。

パラメータの追加をクリックします。


以上でRESTソース操作の設定は完了です。


ページ・デザイナにて従業員編集の画面を開きます。

プロセスのプロセス・フォーム従業員編集を選択し、ビルド・オプションを使ってコメント・アウトします。削除しても構いません。


代わりになるプロセスを従業員の更新として作成します。

識別タイプとしてAPIの呼び出しを選択します。設定タイプREST Sourceを選択します。RESTソースとしてoracle.example.hr操作としてPUT - employees/{id}を選択します。

サーバー側の条件ボタン押下時としてSAVEを指定します。


パラメータidを選択し、アイテムとしてP3_EMPNOを割り当てます。


それ以外はパラメータ名とページ・アイテム名がページ番号の部分を除き一致しているため、自動的にアイテムが割り当たっています。


HIREDATEについては、REST API側が受け付ける日付フォーマットが英語になっています。そのためパラメータHIREDATEを選択し、タイプ言語としてPL/SQLを選択して、PL/SQL式として以下を記述します。

to_char(to_date(:P3_HIREDATE,'YYYY/MM/DD'),'DD-MON-YYYY','NLS_DATE_LANGUAGE=American')

送受信ともISO8601形式に合わせるのが適切でしょう。


以上でフォームの更新プロセスの入れ替えは完了です。

アプリケーションを実行し、従業員のデータが編集できることを確認します。


本記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。