2015年6月10日水曜日

SSJSで他のWebAPIにアクセスする

みなさん!XPages開発してますか?!

 今回は、Notes/DominoのQAサイト「qA9」で質問に上がった、SSJSから他のWeb APIを呼び出す方法について解説します。

 サンプルDBはこちらから ntf ファイルをダウンロードできます。
 動作確認は、Domino Designer 9.0.1 FP3 で行っています。

Apach HTTP Clientのインポート

  Web APIにアクセスするためには、HTTPで通信する必要があります。しかし、SSJSにはHTTP通信するためのクラスやオブジェクトはありません。なので、Javaを利用します。
 Javaに標準で搭載されているHTTP Clientのクラスを使ってもいいのですが、Apache HTTP Clientを利用すると何かと便利なので、そのライブラリをインポートするところからはじめましょう。

 まず、Aapache HTTP Clientのサイトから、ライブラリをダウンロードします。
ここでは、バージョン4.5のzipを落としましょう。

http://hc.apache.org/downloads.cgi

ZIPの中に"lib"フォルダがあるので、ここから下記のファイルを取得します。
  • httpclient-4.5.jar
  • httpcore-4.4.1.jar


これを対象のDBにインポートします。

ここまではOK?

HTTPでコールするためのオブジェクトをSSJSで作成する

 上のインポートでSSJSからApache HTTP Clientを使用することができるようになりました。ただ、これでは少々使いにくいので、簡単にGET/POSTできるようにSSJSで関数を作ってしまいましょう。


var HttpClient = {};

// GETでWebサービスを呼び出します
// HTTPレスポンスのcontent-typeは、text/* である必要があります。
// パラメータ
//   url: 呼び出し先のURLを指定します。URLパラメータが必要であればそれもつけたものを設定します。
// 戻り値
//   オブジェクト: 下記項目を持ったオブジェクトを返します。
//                 status: レスポンスのHTTPステータス番号
//                 body:   レスポンスの内容(テキスト)
HttpClient.httpGet = function httpGet(url){
 var result = {};
 //Apache HTTP Clientのデフォルトの設定でHTTPClientを生成
 var jClient = org.apache.http.impl.client.HttpClients.createDefault();
 //GETメソッドを作成
 var httpGet = new org.apache.http.client.methods.HttpGet(url);
 //GETでコール
 var response = jClient.execute(httpGet);
 //レスポンスのステータスを取得
 var responseStatus = response.getStatusLine().getStatusCode();
 result.status = responseStatus;
 //レスポンスのBodyを取得して、文字列に変換
 result.body = org.apache.http.util.EntityUtils.toString(response.getEntity(), 'UTF-8');
 return result;
};


//POSTでWebサービスを呼び出します
//HTTPレスポンスのcontent-typeは、text/* である必要があります。
//パラメータ
//  url: 呼び出し先のURLを指定します。URLパラメータが必要であればそれもつけたものを設定します。
//  formParam: フォームとして送られるパラメータをオブジェクトで渡します。
//呼び出し例
//var name:com.ibm.xsp.component.xp.XspInputText = getComponent("name");
//var prefix:com.ibm.xsp.component.xp.XspInputText = getComponent("prefix");
//var params = {
// name: name.getValueAsString(),
// prefix: prefix.getValueAsString()
//};
//var ret = HttpClient.httpPostByForm("http://localhost:8080/HttpClient.nsf/api.xsp/restAPI", params);
//requestScope.put('status', ret.status);
//requestScope.put('body', ret.body);

HttpClient.httpPostByForm = function httpPost(url, formParam){
 var result = {};
 var jClient = org.apache.http.impl.client.HttpClients.createDefault();
 //Formの準備
 var formParams = new java.util.ArrayList();
 for(key in formParam){
  var val = formParam[key];
  formParams.add(new org.apache.http.message.BasicNameValuePair(key,val));
 }
 var postEntity = new org.apache.http.client.entity.UrlEncodedFormEntity(formParams, 'UTF-8');
 var httpPost = new org.apache.http.client.methods.HttpPost(url);
 httpPost.setEntity(postEntity);
 var response = jClient.execute(httpPost);  
 var responseStatus = response.getStatusLine().getStatusCode();
 result.status = responseStatus;
 if(responseStatus == 200){
   result.body = org.apache.http.util.EntityUtils.toString(response.getEntity(), 'UTF-8');
 }else{
  result.body='';
 }
 return result;
};

使い方は、サンプルDBやコメントにも書いていますので割愛。

今回は、GETとフォームの値を送信するPOSTの関数を作成しました。
至極簡素な関数で、戻りはテキストしか想定していません。
認証が必要な場合は、Basic認証やダイジェスト認証をHTTPヘッダに埋め込む必要があります。
その場合は、「UsernamePasswordCredentials」クラスや「BasicAuthCache」クラス、「BasicScheme」クラスなどを使用して、HTTPリクエストヘッダに登録することができます。

詳しくは、「apache httpclient basic認証」でぐぐってみてください。

3 件のコメント:

  1. > Apache HTTP Clientを利用すると何かと便利

    確かに使ってますが、「何かと」が何かわかってません(- -;
    その辺を解説していただけるととても嬉しいです。

    返信削除
  2. あはは。誤魔化したところつかれたー。
    Javaが標準で持ってるクラスでは、「java.net.URLConnection」を使いますが、例えばフォームを送信しようとすると、そこからリクエストBodyのストリームを取得して、フォームのkey/valueをURIエンコードかけた上で"name=ebihara&prefix=Mr"みたいな文字列をストリームに書き込む、などの処理が必要になります。
    また、レスポンスBodyの取得も、bufferReaderなどを利用してストリームから読み取ってバイト配列を文字列に変換・・・などが必要です。
    Apache Http Clientでは、そういった処理をラップしていて簡単にHTTPリクエストが作成できるような工夫がされています。

    返信削除
  3. > あはは。誤魔化したところつかれたー。
    いえいえ。ホントに良くわからないままだったので(Java系のサンプルを探すと、みんなApache HTTP Clientを使ってる)、気になっていたのでした。

    おかげさまですっきりしました。丁寧な解説、ありがとうございます!!

    返信削除