2025年4月18日金曜日

ORDS REST APIでHello Worldを返すハンドラをTypeScriptで記述する

Oracle REST Data ServicesのREST APIのハンドラをTypeScriptで記述してみます。ORDS 24.1.1から、ORDSのREST APIのハンドラとしてMLEで実行されるJavaScriptのコードを登録できるようになっています。この機能拡張については、記事「ORDSのハンドラをMLEのJavaScriptで記述する」で紹介しています。

SQLclのmleコマンドがRollupをサポートしたため、少し設定を追加することでTypeScriptのトランスパイルもできます。以下のHello Worldを出力するコードをORDS REST APIのハンドラとして実行するための、一覧の作業手順を確認します。

作業には、主にVS Codeを使用します。
// hello.ts
// My first Typescript Hello on MLE.
export async function hello( req:any, resp:any ) {
    resp.content_type('text/plain');
    resp.status(200);
    resp.send('Hello World - TypeScript !');
}
ORDS REST APIを呼び出すと、Hello World - Type Script !と返されます。

% curl http://localhost:8181/ords/apexdev/tshello/tshello

Hello World - TypeScript !

% 


作業はOracle Database 23ai FreeをmacOS上でコンテナとして実行して、その上にOracle APEXをインストールした環境で行います。Oracle Database 23aiであれば、Always FreeのAutonomous Databaseやその他の環境でも、手順に大きな違いはないはずです。

今回の作業では、APEXのワークスペース・スキーマに接続して、ORDS REST APIを作成します。あらかじめSQLワークショップRESTfulサービスを開き、ORDSにスキーマを登録しておきます。また、VS Codeから接続するため、APEXのワークスペース・スキーマにパスワードを設定しておきます。


MLEのJavaScriptを使った作業を行うために、APEXのワークスペース・スキーマに以下の権限を追加で与えます。Autonomous Databaseであれば管理者ユーザADMIN、Oracle Database 23ai Freeであれば、ユーザーSYSで以下のコマンドを実行します。
grant execute on javascript to [APEXワークスペース名];
grant execute dynamic mle to [APEXワークスペース名];
grant create mle to [APEXワークスペース名];
以上で準備は完了です。

最初に作業ディレクトリとしてts-helloを作成し、プロジェクトを初期化します。

npm -v
mkdir ts-hello
cd ts-hello
npm init -y


% npm -v

10.9.2

% mkdir ts-hello

% cd ts-hello

ts-hello % npm init -y

Wrote to /Users/username/Documents/ts-hello/package.json:


{

  "name": "ts-hello",

  "version": "1.0.0",

  "main": "index.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "keywords": [],

  "author": "",

  "license": "ISC",

  "description": ""

}




ts-hello % 


TypeScriptのトランスパイルとRollupの実行に必要なパッケージをインストールします。

npm install --save-dev typescript rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript tslib

ts-hello % npm install --save-dev typescript rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript tslib


added 2 packages, and audited 27 packages in 2s


5 packages are looking for funding

  run `npm fund` for details


found 0 vulnerabilities

ts-hello % 


TypeScript設定ファイルを作成します。

npx tsc --init

ts-hello % npx tsc --init


Created a new tsconfig.json with:                                               

                                                                             TS 

  target: es2016

  module: commonjs

  strict: true

  esModuleInterop: true

  skipLibCheck: true

  forceConsistentCasingInFileNames: true



You can learn more at https://aka.ms/tsconfig

ts-hello % 


ここからはフォルダts-helloをVS Codeで開いて作業を進めます。

tsconfig.jsonを以下の内容に変更します。
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "outDir": "dist",
    "esModuleInterop": true,
    "strict": true
  },
  "include": ["src"]
}

ファイルrollup.config.mjsを作成し、以下の内容を記述します。
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";

export default {
  input: "src/hello.ts",
  output: {
    format: "esm",
  },
  plugins: [resolve(), commonjs(), typescript()],
};

フォルダsrcを作成し、その下にhello.tsを作成します。コードとして以下を記述します。
// hello.ts
// My first Typescript Hello on MLE.
export async function hello( req:any, resp:any ) {
    resp.content_type('text/plain');
    resp.status(200);
    resp.send('Hello World - TypeScript !');
}

フォルダdb_scriptsを作成し、ORDS REST APIのモジュール、テンプレートおよびGETハンドラを作成するSQLスクリプトを保存します。ファイルsetup_handler.sqlを作成し、以下のコードを記述します。

declare
l_exists integer;
l_module_id user_ords_modules.id%type;
l_template_id user_ords_templates.id%type;
begin
/* prepare ords module for tshello */
begin
select id into l_module_id from user_ords_modules where name = 'tshello';
dbms_output.put_line('Module tshello exists');
exception
when no_data_found then
/* create tshello module */
ords.define_module(
p_module_name => 'tshello'
,p_base_path => '/tshello/'
,p_items_per_page => 25
,p_status => 'PUBLISHED'
,p_comments => null
);
select id into l_module_id from user_ords_modules where name = 'tshello';
dbms_output.put_line('Module tshello created');
end;
/* prepare ords template for tshello */
begin
/* l_template_id is never be used for handler definition */
select id into l_template_id from user_ords_templates where uri_template = 'tshello' and module_id = l_module_id;
dbms_output.put_line('Template tshello exists');
exception
when no_data_found then
/* create tshello template */
ords.define_template(
p_module_name => 'tshello'
,p_pattern => 'tshello'
,p_priority => 0
,p_comments => null
);
select id into l_template_id from user_ords_templates where uri_template = 'tshello' and module_id = l_module_id;
dbms_output.put_line('Template tshello created');
end;
/* define handler */
ords.define_handler(
p_module_name => 'tshello'
,p_pattern => 'tshello'
,p_method => 'GET'
,p_source_type => 'mle/javascript'
,p_mle_env_name => 'TS_HELLO_ENV'
,p_source =>
q'~
( req, resp ) => {
const { hello } = await import('tshello');
await hello( req, resp );
}~'
,p_comments => null
);
dbms_output.put_line('GET Handler for template tshello created or updated');
end;
/
commit;


ORDSのハンドラには以下のコードを登録し、MLEモジュールからエクスポートされているファンクションhelloを呼び出します。
( req, resp ) => {
    const { hello } = await import('tshello');
    await hello( req, resp );
}
以上でファイルの準備は完了です。これよりデータベースへのREST APIのデプロイを始めます。

SQL Developer Extension for VS Codeを開き、REST APIをデプロイするスキーマへの接続を作成します。


作成した接続でデータベースに接続して、接続の上で右クリックしてコンテキスト・メニューを表示します。メニューにあるSQLclを開くを実行します。


SQLclより以下のコマンドを実行し、TypeScriptのソース・コードhello.tsから、MLEモジュールTS_HELLOを作成します。

cd [ts-helloのあるディレクトリ]/ts-hello
mle create-module -bundler rollup -bundler-config rollup.config.mjs -filename src/hello.ts -module-name TS_HELLO -replace


接続の下にあるJavaScriptモジュールを開き、TS_HELLOが作成されていることを確認します。

MLE環境のノードにある + (作成)アイコンをクリックし、作成画面を開きます。MLE Environment NameTS_HELLO_ENVを入力し、適用をクリックします。


MLE環境の下にTS_HELLO_ENVが作成されます。その上で右クリックをしてコンテキスト・メニューを開き、Add Imports...を実行します。


Module Name"スキーマ名"."TS_HELLO"を選択します。Import Nametshelloと入力します。

適用をクリックします。


再度MLE環境のTS_HELLO_ENVを選択し、Import Nameとしてtshelloが追加されていることを確認します。


以上で、MLEのセットアップは完了です。

ORDS REST APIのモジュール、テンプレートおよびGETハンドラを作成します。必要な処理はsetup_handler.sqlにすべて記述されています。

setup_handler.sqlを開き、スクリプトの実行をクリックします。


初回実行では、実行先の接続の選択を求められます。MLEモジュールやMLE環境を作成した接続を選択します。


スクリプト出力が以下のようであれば、ORDS REST APIのモジュール、テンプレートおよびハンドラが作成されています。
Module tshello created
Template tshello created
GET Handler for template tshello created or updated


PL/SQLプロシージャが正常に完了しました。


コミットが完了しました。

以上でORDSのREST APIを呼び出せるようになりました。モジュール・ベース・パスはtshello、URLテンプレートはtshelloなので、呼び出すORDS REST APIの完全なURLは、以下のようになります。

http[s]://ホスト名:ポート番号/ords/ワークスペース別名/tshello/tshello

SQLワークショップのRESTfulサービスを開き、モジュールtshelloに含まれるテンプレートtshelloを開いて、完全なURLを確認できます。


curlコマンドで完全なURLを呼び出します。

curl http[s]://ホスト名:ポート番号/ords/ワークスペース別名/tshello/tshello

% curl http://localhost:8181/ords/apexdev/tshello/tshello

Hello World - TypeScript !%


以上で、hello.tsに記述したコードをORDS REST APIから呼び出すことができました。

hello.tsの内容を少し変更して、再デプロイに必要な作業を確認します。

VS Codeでhello.tsの内容を以下に変更し、保存します。
// hello.ts
// My first Typescript Hello on MLE.
export async function hello( req:any, resp:any ) {
    resp.content_type('text/plain');
    resp.status(200);
    resp.send('Hello World Again - TypeScript !');
}

SQLclを開き、mleコマンドを再度実行します。mleコマンドにオプション-replaceを与えているのでMLEモジュールTS_HELLOが置き換えられます。

cd ~/Documents/ts-hello
mle create-module -bundler rollup -bundler-config rollup.config.mjs -filename src/hello.ts -module-name TS_HELLO -replace


mleコマンドはメッセージ「MLEモジュールTS_MODULEが作成されました。」と返して、正常終了します。

一点、問題があります。

現行のSQL Developer Extension for VS Code 25.1の接続の下にあるJavaScriptモジュールTS_HELLOの内容は、MLEモジュールが置き換えられても更新されません。JavaScriptモジュール上のリフレッシュをクリックしても、更新されません。


一旦接続を切断し再接続を行うと、置き換えられたMLEモジュールの内容が表示されます。VS Code側での表示上の問題であり、データベースに作成されているMLEモジュールは更新されているので気にしなくても良いのですが、バンドル化されたコードを確認する際には注意が必要です。

MLEモジュールが置き換えらえれると、そのMLEモジュールを含むMLE環境はステータスがインバリッドに変わります。再度バリッドに戻すにはコンパイルする必要があります。

MLE環境TS_HELLO_ENVに赤い X マークがついています。これはステータスがインバリッドであることを意味しています。MLE環境のTS_HELLO_ENV上で右クリックをしてCompile...を実行します。


コンパイルの実行の確認を求められるので、適用をクリックします。


MLE環境のコンパイルが完了すると、TS_HELLO_ENVの赤い X マークが消えます。


再度curlコマンドでORDS REST APIを呼び出すと、更新されたhelloが呼び出されていることが確認できます。

% curl http://localhost:8181/ords/apexdev/tshello/tshello

Hello World Again - TypeScript !% 


今回の記事は以上になります。

Oracle REST Data ServicesのRESTサービスの開発の参考になれば幸いです。