RPGでウェブ・サービスを利用する
RPGDateのウェブ・サービス・コンシューマ・コードを記述して手持ちのスキルを活用する
ウェブ・サービスは広範な意味を持つ用語で、XML、WSDL、SOAP、JSON、Ajaxなどといった多数のテクノロジを含んでいます。しかしその中核となる概念はシンプルです。ウェブ・サービスはサーバーが他のサーバーと情報をシェアすることです。ウェブ・サービスのコンシューマ(利用者)となるには、コンシューマ側のサーバーがサービスのプロバイダである他のサーバーへの呼び出しを起動します。プロバイダはコンシューマからのリクエストに基づいて応答を返します。
ウェブ・サービスを使用する主な利点は、技術的に中立な方法でバラバラに存在している情報源から情報を共有して収集することができるということです。たとえば、顧客のUPS出荷状況に関する情報を表示してクレジット・カードの支払いを即座に処理して注文を確認するというウェブサイトを構築することができます。このウェブサイトの裏側では、アプリケーションがUPSから情報を入手するか、またはChase Paymentech社などといったクレジット・カード処理機構から承認コードを入手しているかもしれません。
上記のようなテクノロジのどれかを使用することができますが、キーとなるテクノロジはHTTPプロトコルです。このプロトコル(より一般的にはそのセキュア版であるHTTPS)はほとんどの場合ウェブ・サービス・アプリケーション用の輸送メカニズムとなっていて、2台のサーバーが共通して持つ必要のある唯一のテクノロジです。コンシューマとプロバイダが会話をするにはIBM iのマシンがLinuxやWindowsのマシンと話をするなどといったことは重要ではありません。コンシューマがプロバイダに対して何かを要求する際、その応答はブラウザからのリクエストを受け取ったときとほぼ同じ方法で作成されます。つまり、URLにマッピングされているサーバーに対してHTTP上でURLリクエストが送信されるという方法です。サーバーはデータを返すことで応答します。サーバーはウェブ・サーバー・ソフトウェアを使用してその応答を提供しますが、それは一般のHTMLページが返信されるのと同様です。
本稿では、コンシューマとしてのウェブ・サービスに焦点を当てます。典型的なニーズとしては顧客に対して注文品の送料に関する情報を提供する、などがあります。UPSはウェブ・サービスを使用して送料の比較や配送状況などといった情報を要求できるような一連のAPIを提供しています。これらの情報を取り出すためのウェブ・サービスをサイトの裏側で使用してウェブ・アプリケーション内に直接埋め込むことで、提供しているアプリケーションから別のページに離れてナビゲーションする手間が省けます。ウェブ・サービスを利用すると提供しているアプリケーションが使いやすくなる一方で、顧客に対して有益な情報を提供することができます。
IBM iではWebSphere、Apache、またはIBMの内部Javaウェブ・サーバーのいずれかを稼動しているのが一般的です。本稿では、Apacheウェブ・サーバーを使用しています。それはこの分野でRPGがどのような役割を果たすのかについて興味があるからです。Apacheウェブ・サーバーはCGIプロトコルを直接介してRPGを使用するための機能を提供しています。Apacheサーバーは無償で利用でき、多くのプラットフォーム上で広く利用されていて、スケーラビリティも高いサーバーです。我が社の顧客はApacheサーバー上でRPGベースのウェブ・アプリケーションを何千個と稼動していますので、私はRPGとApacheが一緒になってウェブ・アプリケーション構築のテクノロジの確固とした基礎をなしていることを実体験として知っています。
必要なツール
RPGのサンプル・コードをいくつか見る前にRPGとウェブ・サービスを組み合わせて使用する際に必要となるツールについて説明しましょう。RPGはウェブ・サービスの提供と利用の両方の機能をネイティブで備えていますが、この機能をゼロからコーディングするのは時間がかかりますしRPGの特殊なスキルを必要とします。コード・ライブラリが役に立つのはこのような時です。IBM iのネイティブ・コードを生成するのに特化した商用ツール(たとえばRPG、ILEなど)がいくつか利用可能になっており、アプリケーションの生成からXMLの構文解析まで、ウェブ開発を簡素化してくれます。
まず手始めにオープン・ソースのソース・コードのライブラリをいくつか使用するのも良いでしょう。CGIDEV2 (Easy400に掲載)はウェブ・サービス(あるいはついでに従来のウェブ・ページも含めて)を提供する際に使用することができる一連のRPG関数群です。またCGIDEV2にはIFSファイルの処理などといった他の一般的なウェブ・アプリケーションのシナリオ用の関数も含まれています。CGIDEV2はウェブ・プログラミングの機能の入門には適したツールですが、PHPなどといった他のウェブ言語が備えているコアなウェブ関数の一部を備えていません。たとえば、CGIDEV2にはPHPが備えているようなネイティブのセッション管理機能がありませんので、自分で管理しなければなりません。セッション管理は、ユーザーがアプリケーションとやり取りする際にサーバーとクライアント(ブラウザ)が連携できるようにする際のアプリケーションの状態を追跡するのに重要な機能です。
ウェブ・サービスを利用するにはスコット・クレメント氏が作成したHTTPAPIを使用することをお勧めします。このライブラリを使用すると、HTTPリクエストを自分が作ったプログラムからHTTPまたはHTTPSプロトコルを介して直接送信することができます。RPGをそのまま使ってHTTP上でリクエストを送信するのはかなり容易です。難しいのはHTTPSを使用する部分で、ここでスコットさんのAPIを使用すると便利なのです。また同氏はXML構文解析機能もこのAPIの中に入れています。これは、もともとはCで記述されたExpatの実装です。ウェブ・サービスのプロバイダはXMLドキュメントの形式で情報を返してくることが多いので、XML構文解析機能があることは重要です。Expatを使用すると任意のXMLドキュメントの中で情報をすばやく検索することができます。UPSのAPIの場合、計算された送料がXMLドキュメントの中に埋め込まれて戻されます。Expatの詳細についてはこちらを参照ください。(スコットさんのユーティリティは無償で利用できオープン・ソースでもあります。)
前述のツールのライブラリをインストールしたら、RPGコードを記述する準備完了です。両ツールとも使用できる関数を宣言するためのファイルを備えています。
プログラム例の動作
例としてUPSのウェブ・サービスを呼び出して、ある住所から別の住所へ荷物を送付するための費用という1つの値を受けとるRPGプログラムを見てみましょう。このプログラム例は、ブラウザ・ベースのアプリケーションからではなくコマンド・ラインから実行できる点に注意してください。つまり、既存の緑色画面アプリケーションをブラウザ・アプリケーションに組み入れるだけでなく、ウェブ・サービスで拡張できるということです。
UPS APIを使用するには開発者としてサインアップしなければなりません。UPSがユーザーIDとパスワードとアクセス・キーを発行してくれ、UPSのサービスを利用するときにUPSに対して送信するXMLドキュメントの中にこれらを埋め込みます。(詳細はUPS developer siteを参照してください。)
図1のコードを詳しく見てみましょう。まず(HTTPAPIディレクトリをバインドして) H仕様とcopy文を使用してスコットさんのHTTP 1.2 APIを取り入れ、関数のプロトタイプをインクルードします(図1の赤帯箇所)。
図1: 送料を取得するためのコード
その他いくつか関数のプロトタイプも定義します。たとえば、XMLの構文解析、IFSファイルの処理などの関数です。私はこれらの関数をコード・ライブラリに作業用?として持っています(簡潔にするために本稿ではその詳細については述べません)。IFSファイル処理用の関数はかなり一般的で、私のプログラム例ではなくスコットさんのXML関数を使用してXMLの構文解析を行うこともできます。またIBMのXML toolkit for IBM i (V6R1以前では5733XT1、V6R1およびそれ以後では5733XT2 )を選択することもできます。これはXML-INTO等といったRPG用のopcodeを提供しています。本稿のプログラム例で使用しているXML関数は簡単で使いやすく、読めばその動作がわかるようになっています。
UPSのウェブ・サービスを利用するには、受け取りたい情報に関する説明が記載されたXMLドキュメントが必要です。図2にこの情報をコンパイル時配列のXMLArrayとして記載しています。
図2: UPSに送信するXML
大きな定数はD仕様やC仕様に直接埋め込むよりはコンパイル時配列として定義するほうが簡単であることが多いと私は思います。そうしておくと改行を気にせずに済み、データもソースの最後に隠しておくことができます。これがもし実運用システムである場合はソース・メンバーやIFSファイルの中にこの情報を格納したいところでしょう。図2を見てお分かりの通り、このドキュメントには送付元と送付先のアドレス、荷物の種類、荷物の重量が含まれています。UPSにはUPS標準を使用して送付する際の費用を教えて欲しいのです(図2の赤帯箇所)。
次に、ランダム・ファイル名を生成してウェブ・サービスを呼び出した結果を格納します(図3)。
図3: ランダム・ファイル名の生成
スコットさんの関数は結果を含んだ大きな変数かまたはIFSファイルを返します。結果がIFSファイル内に保存されている方がデバッグが楽なので私はその方が好きです。生成されたファイルを開いてPCのエディタで簡単に表示させることができます。この場合、ファイルを/webroot/webtest/というIBM iの一時ディレクトリ上に保存します。保存場所は自分で選択することができます。
図4の1つ目の赤帯部分で、スコットさんのhttp_url_post関数を使用してウェブ・サービスの呼び出しを起動しています。
図4: ウェブ・サービス呼び出しの起動
最初のパラメータである https://wwwcie.ups.com/ups.app/xml/Rate はウェブ・サービスのアドレスです。UPSはwwwcieとwwwという2つのサーバー・アドレスのプレフィックスを用意しています。 wwwcieのアドレスはテスト・サーバーを指し示しています。ウェブ・サービスのプロバイダではこうするのが一般的です。テスト・サーバーはプロバイダの実運用サーバーに影響を与えることなくプログラムを試すサンドボックスの機能を提供してくれます。Chase Paymentechも似たような方法でクレジット・カードの検証及び承認用のAPIを用意しています。https: を使用するのはUPSへの接続にSSLを使用することを保証するものですが、暗号化されたデータが送受信されます。
次の2つのパラメータはUPSに送ったXMLデータ(変数XMLIn)を指し示しています。最後のパラメータ(変数rspxmlfile)はUPSから戻ってくる出力のXMLを保持するファイルを指し示しています(図3の最後の行)。
図4の2つ目の赤帯部分では、戻ってきたXMLを読んで大きな変数に値を埋めて構文解析の準備をします。
UPSから戻ってきたXMLの例を図5に示します。
図5: UPSから戻ってきたXML
XML変数を取得したらparseshipcostというサブ・ルーチンを使用して構文解析します(図6)。ここではXMLノードMonetaryValueを探しており、その親はTotalChargesで輸送費と手数料を含んだ荷物の送料がそこに入っています。
この簡単な例では1つの値だけを取り出しています。これと同様の関数呼び出しを使用すれば前述の2つの値を簡単に見つけることができます。たとえば次のように使います。
コードの残りの部分は想定されるエラーの処理用です。送信したXMLドキュメント中にUPSがエラーを検出したときは、戻ってきたドキュメント中にErrorCodeというノードがあるのでそれを調べます。以上です。すべてのウェブ・サービスでXMLを送信または受信する必要があるわけではありませんが、ここでご紹介した概念を理解しておくことはごく一般的なことです。
より多くの価値を提供する
ウェブ・サービスは簡単に言えば従来のRPGのプログラム対プログラムの呼び出しに過ぎません。従来のプログラム呼び出しとの違いはインタフェースです。ウェブ・サービスはテクノロジへの依存度が相対的に低い点がすばらしいです。プロバイダはコンシューマのコードがJavaScriptで書かれているのか、Perl、PHP、C、RPGで書かれているのかは関係ありません。RPGを使用するとすでに持っているプログラミング言語スキルを活用することができます。従来のプログラミングと共通したテクノロジ上の要件はHTTP/HTTPSトランスポートと、サーバーから外部世界へのインターネット接続が利用できるということです。このテクノロジが設定されていれば、多くのサード・パーティのソースからの情報や処理を統合して、エンド・ユーザーに対してより多くのビジネス・アプリケーションの価値を提供することができます。