背景
Oracle REST Data ServicesがOracle Autonomous Database(ATP / ADW)で利用可能になりました。
ネイティブのOracle RESTデータサービス(ORDS)を使用し、Autonomous Database(自律型データベース)用のRESTサービスを開発およびデプロイできます。
そこで、ADB上のORDSにて、典型的なブログアプリケーション(REST API)を作ってみました。
環境準備・接続確認
■ ATPインスタンスの作成
Autonomous Database では、数回クリックするだけで簡単にインスタンスが作成できます。
(CPU、ストレージが不足した場合は、ダウンタイムなしでいつでもOCPUとストレージを拡張できます。)
ATPインスタンスが起動しました。
■ ATPインスタンスへの接続の作成(SQL Developer)
[DB Connection]ボタンをクリックして、認証情報(Wallet)ファイルをダウンロードしてください。
Walletファイルをダウンロードしたら、SQL Developerで新しい接続を作成します。
■ REST APIで操作対象とするスキーマ、および表を作成(users表、blogs表)
SQL Developerより以下を実行します。
-- Create Application User by ADMIN.
CREATE USER ORDSBLOG IDENTIFIED BY <PASSWORD>;
-- Grant privileges
GRANT CREATE SESSION TO ORDSBLOG;
GRANT DWROLE TO ORDSBLOG;
GRANT UNLIMITED TABLESPACE TO ORDSBLOG;
SQL Developerperにて、新ユーザ(ORDSBLOG)の接続を作成します。接続名を右クリックし、「Enable REST Services...」をクリックします。
「Enable schema」チェックボックスをオンにして、このスキーマのRESTサービスを有効にします。
もしくは以下をadminユーザにて実行すると、ORDSBLOGスキーマのRESTサービスも有効できます。(★)
BEGIN
ORDS_ADMIN.ENABLE_SCHEMA(
p_enabled => TRUE,
p_schema => 'ORDSBLOG',
p_url_mapping_type => 'BASE_PATH',
p_url_mapping_pattern => 'ordsblog',
p_auto_rest_auth => TRUE
);
COMMIT;
END;
/
以下はORDSBLOGユーザにて実施してください。
-- Create tables
CREATE TABLE ORDSBLOG.USERS (
ID NUMBER GENERATED ALWAYS AS IDENTITY,
NAME VARCHAR2(200) NOT NULL,
CONSTRAINT USER_ID_PK PRIMARY KEY (ID)
);
CREATE TABLE ORDSBLOG.BLOGS (
ID NUMBER GENERATED ALWAYS AS IDENTITY,
AUTHOR_ID NUMBER NOT NULL CONSTRAINT USER_ID_FK
REFERENCES ORDSBLOG.USERS(ID),
TITLE VARCHAR2(200),
CONTENT VARCHAR2(32767),
CONSTRAINT BLOG_ID_PK PRIMARY KEY (ID)
);
■ 各テーブルに対するRESTサービスの有効化
以降の手順はSQL DeveloperでORDSBLOGユーザでログインしなおしてから実施してください。
[Authorization required]チェックボックスをオフにします。
(簡単にするためにここでは認証は不要として記載します。認証ありの場合は後述)
作成する内容を確認して[Finish]をクリックします。
これで、テーブルusers用のREST APIを使用する準備が整いました。
■ URIエンドポイントの取得、動作確認
APIにアクセスするためのURIエンドポイントの取得はいくつか方法がありますが、ここでは、作成したATPインスタンスのサービスコンソールから取得します。
OCIのコンソールを開いてATPインスタンスのページに移動し、Service Consoleをクリックします。
次に[Development]をクリックし、[SQL Developer Web]タイルを右クリックしてそのリンクをコピーします。
以下のようにリンクを得るべきです。admin / _sdw /?nav = worksheet
の部分を、作成したスキーマ名とRESTサービスを有効にしたテーブル名に置き換えます。
旧:https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/admin/_sdw/?nav=worksheet
新:https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/ordsblog/users/
下のスクリーンショットに示すように、このURIエンドポイントに直接アクセスすることでJSON形式の応答を取得できるはずです。
(RESTサービスを有効にしたときに承認チェックを有効にすれば、認証の設定が可能)
尚、ここでは便利なツールpostmanを使ってREST APIをテストしていますが、その他CURL等を利用して確認することも可能です。
テーブルusersにはレコードがないので、itemsは[]
です。
テーブルのユーザーのメタデータを確認するために、 describeby
リンクをクリックすることもできます。
ご覧のとおり、ADBインスタンスがある限り、RESTサービスを有効にするだけで、REST APIからテーブルにアクセスできるようになります。 とても簡単ですね。
ADBでORDSを使用するためのより良い方法
環境構築、接続作成にてまずは簡単にアクセスする方法を記載しましたが、実際には接続ナビゲータバーに表示されている「REST Data Services」の下の[Modules]と[Templates]を使用し、リソースへのアクセスを制御することをお勧めします。
■ RESTサービスの無効化方法
テーブルusersにおける[Enable object]チェックボックスをオフにします。
自分のデータを制御なしで公開することを望む人は誰もいないでしょう。
テーブルusersのRESTサービスが無効になると、同じリンクにアクセスしたときに 404 Not Found
エラーが発生します。 それが私たちが期待していたことです。
モジュール/テンプレート/ハンドラの使用
ユーザを取得するためにモジュール/テンプレート/ハンドラを使ってみます。
モジュールの作成
[REST Data Services]の下の[Modules]を右クリックし、[New Module]をクリックして新しいモジュールを作成します。
Module NameとURI Prefixを入力し、「Publish – Make this RESTful Service available for use」チェックボックスを選択します。
「Next」をクリックしてテンプレートを指定してください。 登録機能を提供するためにこのURIを使います。
要約を確認して、「Finish」をクリックします。
これで、usersというモジュールとnewというテンプレートが作成されました。
これは、以下のようにREST APIエンドポイントを作成しました。
https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/ordsblog/users/new
このリンクにアクセスしようとしても、まだこのエンドポイントにハンドラを追加していないため、404 Not Found
エラーが発生します。
このエンドポイントを使用して登録機能を提供することを計画していましたが、テスト目的で、今のところこのエンドポイント用のGETハンドラーを追加します。
ハンドラワークシートにおいて、テーブルusersに単純なクエリ select * from users
を入力して保存します。
エンドポイントに再度アクセスしてください。
https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/ordsblog/users/new
やった! APIが動作することが確認できました。
新しいユーザーの登録(POST)
このエンドポイントを使って新しいユーザーを登録するために、POSTハンドラを追加しましょう。
テンプレートnewを右クリックして、新しいPOSTハンドラを追加します。
[Apply]をクリックしてください。
POSTリクエストを処理するには少し複雑ですが、入力パラメータと出力レスポンスの内容に注意する必要があります。 以下のように新規ユーザーの作成を処理するプロシージャを使用します。
create or replace PROCEDURE ADD_USER (
P_USER_NAME IN USERS.name%TYPE,
P_OUT_ID OUT USERS.id%TYPE,
P_OUT_TOTAL OUT INTEGER
)
AS
BEGIN
INSERT INTO USERS (name)
VALUES (P_USER_NAME)
RETURN id INTO P_OUT_ID;
SELECT COUNT(id) INTO P_OUT_TOTAL FROM USERS;
EXCEPTION
WHEN OTHERS
THEN HTP.print(SQLERRM);
END;
POSTハンドラで、今作成したプロシージャを呼び出し、リクエストから取得したパラメータを渡します。
BEGIN
ADD_USER(P_USER_NAME => :USER_NAME,
P_OUT_ID => :NEW_USER_ID,
P_OUT_TOTAL => :TOTAL);
commit;
END;
応答として、クライアントが次の動きを決定できるように新しく作成されたユーザーIDを返し、また全ユーザーの総数も返します。 以下のようにパラメータを設定します。
これで、POSTハンドラは準備完了です。 新しいユーザーを作成するためにJSON形式でユーザー情報をポストします。
JSONのキーはハンドラプロシージャの定義と同じである必要があります。
postmanクライアントで、リクエスト・メソッドはPOSTを選択し、エンドポイントURIを入力し、Body / RawセクションにJSON形式でユーザー情報を入力します。 (jsonファイルを使用してrawの代わりにbinaryを選択することもできます)
{
"USER_NAME":"user01"
}
また、ヘッダの "Content-Type"を "application / json"に設定する必要があります。
[Send]ボタンをクリックすると、レスポンスのステータスが200 OK、新しいユーザーIDとレスポンス内のユーザーの総数が表示されます。
SQL Developerでは、新しく作成されたユーザーレコードを確認することもできました。
すべてのユーザーを取得するためのGETハンドラがあることを覚えていますか。 それを試してみましょう。
ユーザープロファイルを確認する(GET)
ユーザーが登録されると、ユーザーのプロフィールを表示するためにユーザー情報を提供する必要があることは明らかです。
これを行うためにshowエンドポイントを作成しましょう。
ユーザー情報を提供するためのGETハンドラを追加します。
ハンドラーでのクエリーは非常に簡単です。クエリーを完了するには、クエリー・パラメーターとしてユーザーIDを提供します。
以下のようにクエリを開始すると、期待通りにユーザー情報が得られます。
https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/ordsblog/users/show?id=6
ブログを処理する
次に、REST APIを介して全てのCRUD動作をテーブルblogsに対して実施してみましょう。
最初のブログを投稿する(POST)
新しいユーザーハンドラと同様に、すでにこれに慣れていると思います。
データ挿入を処理するプロシージャを作成し、POSTハンドラでそのプロシージャを呼び出します。
予想される応答を確認するのに、問題が発生してはいけません。
自分のブログをすべて一覧表示する(GET)
それはまだGETリクエストです、唯一の違いはSQLクエリがブログを検索できるようにユーザーIDを渡すことです。
ブログを更新する(PUT)
以前に投稿したブログを更新したい場合はどうなりますか? そのためにはPUTメソッドを使用してください。
updateテンプレートを作成します。
POSTも動作しますが、更新作業を行うためのPUTハンドラを追加します。REST APIのベストプラクティスによれば、意図を示すためにPUTを使用する必要があります。
ブログの更新を処理するプロシージャは作成するのと似ています。
PUTハンドラーでブログ更新プロシージャを呼び出します。
postmanのクライアントでは、リクエストメソッドをPUTに設定し、Bodyセクションに新しいブログ情報を入力します。
更新されたブログを確認してください。
何? ショーブログエンドポイントを持っていませんか? そのようなGETハンドラを実装するのはあなたにとってとても簡単ですよ。
ブログを削除する(DELETE)
ブログ内の何かが古くなっていて、もうそれを残したくない場合は、いつでもブログを削除するためのDELETEハンドラを実装できます。
deleteテンプレートを追加します。
DELETEハンドラを作成します。
削除したいブログのIDを忘れずに渡してください。
postmanのクライアントでは、DELETEとしてリクエストメソッドを選択し、今実装したエンドポイントにリクエストを送信します。
今#2ブログだけを見ることができます。
リソースを保護する
Basic Auth
今までは、誰でも私たちのリソース(ユーザー、ブログ)に対して何でもすることができます。 明らかに、私たちはリソースを保護するようになりました、それはORDSのprivilegesを利用することによってそうすることができます。
[REST Data Services]の下の[Privileges]を右クリックして、新しいPrivilegesを作成します。 Name, Title, Descriptionを入力します。 簡単にするために、1つの特権ですべてのモジュールを保護します。
すべてのモジュール(users, blogs)を[Protected Modules]セクションに追加します。
新しく作成された権限Demoを見ることができます。
ユーザーの情報をもう一度要求しようとすると、下のように401 Unauthorized
エラーが発生します。
Webブラウザを使用してAPIをテストしている場合は、sign inをクリックしてDBユーザー資格情報を入力してパスすることができます。
postmanクライアントの「Authorization」タブで、Basic Authとして「TYPE」を選択し、DBユーザー資格情報を入力します。 リクエストを送信すると、ユーザー情報が表示されます。
OAuthクライアントアプリケーションを登録する
このREST APIを構築する目的は、フロントエンドまたはその他の承認されたサードパーティ製アプリケーションにデータアクセス機能を提供することです。BasicAuthは明らかにそうするための適切な方法ではありません。
OAuth 2.0は、REST APIを提供するHTTPサーバーがエンドユーザーに代わってサードパーティのアプリケーションへのアクセスを制限する手段を提供する標準のインターネットプロトコルです。
- サードパーティ製アプリケーションの作成者は、クライアントの資格情報を取得するためにアプリケーションを登録する必要があります。
- クライアント認証情報を使用して、サードパーティ製アプリケーションはエンドユーザーにアクセスを承認するように促すWebフローを開始します。
前述のように、OAuthを使用することで、クライアントアプリケーションは登録して承認を受けることでREST APIにアクセスできます。 そして幸いなことに、このフローはデフォルトでORDSに組み込まれています。
クライアントアプリケーションを登録するには、次のURLにアクセスする必要があります。
https://<DB_NAME>.adb.<REGION>.oraclecloudapps.com/ords/ordsblog/oauth/clients/
DBユーザー資格情報でサインインすると、まだクライアントが登録されていないことがわかります。
[New Client]をクリックして必要な情報を入力し、[Create New Client]をクリックします。
クライアントは登録されていますがまだ承認されていません。 この登録済みクライアントの詳細を表示するには、「Edit」アイコンをクリックします。
生成されたClient identifier、Unique Value、およびAuthorization URを確認できます。
Authorization URI をクリックして、DBユーザー資格情報でサインインします。 クライアント承認ページが表示されます。 このリクエストを承認するには、承認ボタンをクリックしてください。 拒否も可能です。
リクエストを承認すると、Webページはクライアントを登録したときに指定したURLにリダイレクトされます。 重要な点は、リダイレクトされたURLの次の項目です。
http://example.org/redirect#token_type=bearer&access_token=XErqh-jlHNSoXGe9JX5m7Q&expires_in=3600&state=f084f3c8-d567-e1c8-fb83-81aabacc9b54
- Token_type: bearer
- Access_token: XErqh-jlHNSoXGe9JX5m7Q
- Expires_in: 3600
- State:f084f3c8-d567-e1c8-fb83-81aabacc9b54
Token_typeとaccess_tokenは、クライアントアプリケーションがREST APIにアクセスしようとしたときの重要な情報です。 REST APIへのすべてのリクエストにそれらを含める必要があります。
保護されたREST APIにアクセスするために必要なものがすべて揃ったので、アクセストークンを使用してユーザーのプロファイルを取得してみましょう。
postmanクライアントで、「Authorization Type」を「Bearer Token」として選択し、access tokenを入力します。 それからリクエストを送りなさい、あなたはもう401 Unauthorizedエラーを見るべきではありません。
GETハンドラーだけでなく、正しいアクセストークンを提供する限り、ブログの更新など、すべてのハンドラーにアクセスできます。
逆に、クライアントアプリケーションが正しいアクセストークンを提供できない場合、それは私たちのリソースからブロックされます。
これで、私たちのブログアプリケーション用のセキュアでフル機能の(サンプル)REST APIができました。 そして、Autonomous DatabaseにおけるORDSの基本的な使い方にはもう慣れていると思います。 ORDSとOracle Autonomous Databaseについてもっと知りたい場合は、以下の参考文献を参照してください。
参考
- Developing RESTful Services in Autonomous Database
- Oracle REST Data Services
- Getting Started with Oracle REST Data Services