今回の記事では、ガルーンの「SOAP API」を利用して、ガルーンへのログインからユーザー登録の一連の流れをVBScriptやVBAで実装する際のサンプルコードを紹介します。
尚、APIの基礎やガルーンのSOAP APIの理解を深めていただくために、前編後編で分けて記事を作成していきます。
↓後編はこちらのリンクから
↓ガルーンのメッセージをAPIで送信したい場合はこちら
今回の前編では、APIやSOAP APIの説明とともに、ガルーンへのログインとログアウトまでのサンプルプログラムまでを紹介し、次回の後編で一通りの処理を実装していきます。
APIを利用することのメリット
今回紹介するサイボウズ社のグループウェア「ガルーン」でもそうですし、最近の様々なパッケージソフトやクラウドサービスでは「API」が提供されています。
当記事では、まず最初に、これまで「API」を活用されてこなかった方に対して、APIを活用するメリットを紹介していきます。
そもそも「API」ってなに?
「API」とは「Application Programming Interface」の略称であり、今回紹介するガルーンや、その他の様々なパッケージソフトやクラウドサービスなどの機能を部分的に抜き出して、外部プログラムからそのパッケージソフトやクラウドサービスを操作するための「部品」として提供する仕組みのことを指します。
上記のイメージ図のように、通常は人がそのアプリケーションの入力画面を介してデータ登録を手作業で実施するのですが、APIを活用することで、例えば外部のデータベースからVBSやVBAなどのプログラムを利用して、関連するデータを抽出し、そのデータを元に対象のアプリケーションのAPIを実行してデータ登録の一連の作業を自動化することができます。
APIはデータを登録する処理だけではなく、データを検索したり、取得する処理も提供されています。
操作を外部のプログラムから行うための部品がAPIであり、多くの種類のAPIが提供されているパッケージソフトやクラウドサービスでは、様々な操作が自動化できることになります。
「SOAP API」と「REST API」について
今回のガルーンでは提供されているAPIの種類が大きく二つに分かれており、「SOAP API」と「REST API」の二種類があります。
このそれぞれのAPIはガルーンだけで提供されている仕組みではなく、ウェブの通信を使用したデータ交換やアプリケーション実行に関する共通規格や共通した設計思想であり、知識としても簡単にその違いを知っておくほうが、よりコーディング時の理解も深まると考えます。
よって、その違いについて紹介していきます。
SOAP API
SOAP APIの「SOAP」とは、「Simple Object Access Protocol」の略称であり、Microsoftが開発、規格化し、長らくウェブアプリケーションにおいて使われてきた、ウェブにおけるデータ送信やデータ形式に纏わる共通規格のことを指します。
SOAPでは、厳格に定められたフォーマットのXML形式のデータを使用します。
このXML形式のデータは拡張性が高い反面、記述は煩雑であり、且つ厳格である必要があるため、このXMLの生成及びその解析を規格の古いプログラミング言語で行う場合は、実装に手間が掛かります。
後述するREST APIと比べると、SOAPの名称にある「Simple」とはかけ離れた仕様だと言えます。
後、特徴として、SOAPではAPIを設置するURLは一つか、または最小限の分類分け程度にURLを用意し、機能単位でURLを分けることはしません。
APIに渡すXML内で実行するAPI名を指定します。
後述するREST APIでは、APIごとにURLを分けます。
よって、複雑な業務アプリケーションなどを開発する場合は、一つのURLで各APIを呼び出せるこの仕様の方が実装はしやすいと思います。
他にも色々と特徴はありますが、簡単にまとめると以下です。
尚、ガルーンにおける「SOAP API」は「REST API」よりも先に実装されており、それが理由だとは思いますが、ガルーンのAPIの機能でもSOAP APIの方がREST APIよりも機能が多いため、今回の記事で実施する「ユーザーアカウント登録」といった機能はSOAP APIでしか提供されていません。
REST API
REST APIの「REST」とは「Representational State Transfer」の略称です。
前述したSOAP APIよりも後から生まれたウェブアプリケーションにおけるデータ交換の仕組みです。
SOAPは厳格な共通規格として存在しますが、RESTは規格ではなく「設計思想」です。
よって、その設計思想に準じた実装をしているREST APIを「RESTful API」と呼んだりします。
RESTは以下の特徴があります。
- データフォーマットはJSONが一般的
- 機能ごと(APIごと)に呼び出し先のURLが異なる
- 一度のAPIの実行で完結する(セッション管理をしない)
前述するSOAPと比較した場合は簡単にまとめると以下です。
尚、ガルーンにおける「REST API」は前述したように後発で実装されており、まだ提供されている機能が少ないです。
特にデータを登録するとか更新するといった機能については、SOAPしか対応していないものが多いため、今後REST APIを充実させてもらえるのを期待しています。
サンプルプログラムの仕様について
当項では、今回の記事で紹介するサンプルプログラムの仕様について簡単に定義します。
- パッケージ版ガルーンで検証済み(クラウド版も多分使える)
- プログラミング言語はVBScript
- 認証方式は「WS-Security」を使用
- 「WSDL」の読み込みはしない(VBSやVBAではできない)
- XMLはべた書き又は「MSXML2.DOMdocument」で生成
C#などの別の言語ではこのWSDLをIDEで読み込ませることで、煩雑なXML文の作成処理を自前で実装する必要は無くなります。
ガルーンのSAOP APIにおける「認証方式」の解説
ガルーンのAPIを実行するためには、そのAPIの使用権限を持つユーザー名とそのユーザーのパスワードを使用して認証することが必要になります。
もし認証する仕組みが存在しない場合は、部外者が自社で使用しているガルーンに対して自由にAPIを実行することができてしまうことになります。
当項では、このガルーンの認証方式について解説していきます。
ガルーンのSOAP APIでは二種類の認証方式を選択できます。
ログイン処理を実行して、そのログイン時に生成されるセッションIDを使用して他のAPIを実行する「Cookieを用いた認証方式」と、APIの実行の都度ユーザー名とパスワードもAPIのリクエストに含めて送信する「WS-Securityを用いた認証方式」です。
これらについても適切に理解して利用していきましょう。
「Cookieを用いた認証方式」について
この方式では、ガルーンが提供している各APIを実行する前に、ユーザー名とパスワードをログイン用APIに渡して実行し、ガルーンにログインします。
ログインAPIではパラメーターとして渡された認証情報でログインが成功した際に、そのリクエストに対するレスポンスとして「セッションID」と呼ばれる長い文字列を返します。
セッションIDはサーバー側で接続元クライアントを識別するために生成されるデータであり、そのセッションIDを各APIのリクエストに含めて実行することで、都度ユーザー名とパスワードをリクエストに含めて認証をすることが不要になります。
また、取得したセッションは一定時間で消失しますが、それまでの間はログオフされない限り生成されたセッションIDは有効な状態のままになります。
悪意のある人にそのセッションIDを奪われると、自由にAPIを実行されてしまいます。
よって、APIの呼び出しが完了したら、最後にログオフ用APIでセッションを終了させることが必要です。
尚、ガルーンのSOAP APIのデベロッパーサイトでは高頻度でAPIを実行する場合は「Cookieを用いた認証方式」を推奨しています。
「WS-Securityを用いた認証方式」について
この方式ではAPIを利用したログインやログオフは不要です。
各APIを実行する際に、そのAPIを呼び出す際に、APIを使用するユーザーとパスワードの認証情報も都度リクエストに含めて送信します。
APIの実行の都度認証を行うため、上項の「Cookie方式」のようにセッションIDを取得したり保持する必要がありません。
短時間の間に大量のAPIを実行する場合は、その都度ログイン処理も行っているとサーバーの負荷にも繋がる可能性があるのでリスクがありますが、高頻度で実行する場合でなければ、リクエストの都度認証を行う方が分かりやすいと思います。
尚、弊サイト内のガルーンAPIに関する記事は、この「WS-Securityを用いた認証方式」を元に実装方法を紹介していきます。
今回の記事ではAPIの練習としてログインとログオフの処理を紹介しますが、後編の記事では以下の流れで実装した処理を紹介する予定です。
- データベースから登録及び更新データを取得
- APIでガルーンのログイン名からユーザーIDを取得
- 取得したユーザーIDをもとにAPIでユーザーの登録又は更新を実施
尚、APIの呼び出しや仕様については、サイボウズ社のデベロッパーサイトをご確認ください。
ログイン用APIを実行するサンプルプログラム
まずは、SOAP APIを使用してガルーンにログインするサンプルプログラムを紹介します。
使用するAPI名は「UtilLogin」です。
詳細な仕様は以下のリンクからご確認ください。
上記のリンクを読めばわかりますが、「UtilLogin」では以下のようなxmlを作成してガルーンのAPIにPOSTするだけだということがわかります。
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<Action>UtilLogin</Action>
<Security></Security>
<Timestamp>
<Created>2010-08-12T14:45:00Z</Created>
<Expires>2037-08-12T14:45:00Z</Expires>
</Timestamp>
<Locale>jp</Locale>
</soap:Header>
<soap:Body>
<UtilLogin>
<parameters>
<login_name>xxxxxxxxxx</login_name>
<password>xxxxxxx</password>
</parameters>
</UtilLogin>
</soap:Body>
</soap:Envelope>
尚、最も基本となる処理であり、SOAP APIの入門記事も兼ねているため、XMLをベタ書きした場合の処理と、MSXML2.DOMdocumentでXMLを生成する場合の処理の二通りを紹介します。
個人的には可読性を考慮すると、XMLをベタ書きするほうがまだ読みやすいと思います。
「MSXML2.DOMdocument」でxmlを作成するサンプルプログラム
Option Explicit CONST BASE_URL = "http://example.com/scripts/cbgrn/grn.exe/" CONST LOGIN_API_DIR = "util_api/util/api?" CONST LOGIN_API_NAME = "UtilLogin" CONST LOGIN_USERNAME = "Administrator" CONST LOGIN_PASSWORD = "xxxxxxxxxx" 'ログイン処理を実行します。 If GaroonAPI_Login() Then msgbox "ログインに成功しました。" Else msgbox "ログインに失敗しました。" End If 'UtilLoginを使用しガルーンへログインを実施して、その実行結果を返します。 '引数1:無し '戻り値:真偽 ※ログイン成功:True 失敗:False Function GaroonAPI_Login() Dim objHTTP Dim Full_URL ReDim Para(1,1) Dim objXML Dim HeaderElement Dim RootElement Dim HeaderNode Dim BodyNode Dim childNode1,childNode2,childNode3,childNode4,childNode5 Dim grandChildNode1,grandChildNode2,grandChildNode3 Dim greatGrandchildNode1,greatGrandchildNode2 Dim elm Dim rtnVal Dim ReqXML Full_URL = BASE_URL & LOGIN_API_DIR 'ログインパラメーター Para(0,0) = "login_name" Para(0,1) = LOGIN_USERNAME Para(1,0) = "password" Para(1,1) = LOGIN_PASSWORD 'XML作成処理開始 Set ReqXML = CreateObject("MSXML2.DOMdocument") ReqXML.async = false 'XML宣言を作成します。 Set HeaderElement = ReqXML.createProcessingInstruction("xml","version='1.0' encoding='UTF-8'") 'ルート要素を作成します。 Set RootElement = ReqXML.createNode(1,"soap:Envelope","http://www.w3.org/2003/05/soap-envelope") ReqXML.appendChild(HeaderElement) ReqXML.appendChild(RootElement) 'ルート直下のヘッダノードの作成します。 Set HeaderNode = ReqXML.createElement("soap:Header") 'ルート直下のボディノードを作成します。 Set BodyNode = ReqXML.createElement("soap:Body") '子ノードを作成します。 Set childNode1 = ReqXML.createElement("Action") Set childNode2 = ReqXML.createElement("Security") Set childNode3 = ReqXML.createElement("Timestamp") Set childNode4 = ReqXML.createElement("Locale") Set childNode5 = ReqXML.createElement(LOGIN_API_NAME) 'ヘッダノードに子ノードを追加します。 HeaderNode.appendChild(childNode1) HeaderNode.appendChild(childNode2) HeaderNode.appendChild(childNode3) HeaderNode.appendChild(childNode4) 'ボディノードに子ノードを追加します。 BodyNode.appendChild(childNode5) '子ノードに値を設定します。 childNode1.appendChild(ReqXML.CreateTextNode(LOGIN_API_NAME)) childNode2.appendChild(ReqXML.CreateTextNode("")) childNode4.appendChild(ReqXML.CreateTextNode("JP")) 'ヘッダノード配下の孫ノードを作成します。 Set grandChildNode1 = ReqXML.createElement("Created") Set grandChildNode2 = ReqXML.createElement("Expires") '孫ノードに値を設定します。 grandChildNode1.appendChild(ReqXML.CreateTextNode("2010-08-12T14:45:00Z")) grandChildNode2.appendChild(ReqXML.CreateTextNode("2037-08-12T14:45:00Z")) 'ボディノード配下の孫ノードを作成します。 Set grandChildNode3 = ReqXML.createElement("parameters") 'ヘッダノード配下の子ノードに孫ノードを追加します。 childNode3.appendChild(grandChildNode1) childNode3.appendChild(grandChildNode2) 'ボディノード配下の子ノードに孫ノードを追加します。 childNode5.appendChild(grandChildNode3) 'ボディノード配下のひ孫ノードを作成します。 Set greatGrandchildNode1 = ReqXML.createElement(Para(0,0)) Set greatGrandchildNode2 = ReqXML.createElement(Para(1,0)) 'ひ孫ノードの値を設定します。 greatGrandchildNode1.appendChild(ReqXML.CreateTextNode(Para(0,1))) greatGrandchildNode2.appendChild(ReqXML.CreateTextNode(Para(1,1))) '孫ノードにひ孫ノードを追加します。 grandChildNode3.appendChild(greatGrandchildNode1) grandChildNode3.appendChild(greatGrandchildNode2) 'ドキュメントノードに追加します。 ReqXML.documentElement.appendChild(HeaderNode) ReqXML.documentElement.appendChild(BodyNode) 'XML作成処理終了 '作成したリクエストをPOSTします。 Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP") objHTTP.Open "POST", Full_URL, False objHTTP.send ReqXML.xml If objHTTP.Status <> 200 Then GaroonAPI_Login = False Set objHTTP = Nothing Set ReqXML = Nothing Exit Function End If 'XML解析用のオブジェクトを生成します。 Set objXML = CreateObject("MSXML2.DOMdocument") 'レスポンスをxmlで読み込みます。 objXML.LoadXML(objHTTP.ResponseText) For Each elm In objXML.getElementsByTagName("returns") '目的の値を取得します。 rtnVal = elm.getElementsByTagName("status")(0).text Next If rtnVal = "Login" Then GaroonAPI_Login = True Else GaroonAPI_Login = False End If Set objHTTP = Nothing Set ReqXML = Nothing Set objXML = Nothing End Function
上記が「MSXML2.DOMdocument」を使用してリクエストで使用するxmlを生成する例です。
ご覧の通り、可読性は低いです。
次に、リクエスト用のxmlをべた書きした場合のサンプルプログラムも紹介します。
リクエスト用のxmlを文字列としてべた書きして作成するサンプルプログラム
Option Explicit CONST BASE_URL = "http://example.com/scripts/cbgrn/grn.exe/" CONST LOGIN_API_DIR = "util_api/util/api?" CONST LOGIN_API_NAME = "UtilLogin" CONST LOGIN_USERNAME = "Administrator" CONST LOGIN_PASSWORD = "xxxxxxxxxx" If GaroonAPI_Login Then msgbox "ログインに成功しました。" Else msgbox "ログインに失敗しました。" End If 'UtilLoginを使用しガルーンへログインを実施して、その実行結果を返します。 '引数1:無し '戻り値:真偽 ※ログイン成功:True 失敗:False Function GaroonAPI_Login() Dim objHTTP Dim Full_URL ReDim Para(1,1) Dim objXML Dim sEnv Dim elm Dim rtnVal Full_URL = BASE_URL & LOGIN_API_DIR 'ログインパラメーター Para(0,0) = "login_name" Para(0,1) = LOGIN_USERNAME Para(1,0) = "password" Para(1,1) = LOGIN_PASSWORD Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP") sEnv = "<?xml version=""1.0"" encoding=""UTF-8""?>" sEnv = sEnv & "<soap:Envelope xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">" sEnv = sEnv & " <soap:Header>" sEnv = sEnv & " <Action>" & LOGIN_API_NAME & "</Action>" sEnv = sEnv & " <Security></Security>" sEnv = sEnv & " <Timestamp>" sEnv = sEnv & " <Created>2010-08-12T14:45:00Z</Created>" sEnv = sEnv & " <Expires>2037-08-12T14:45:00Z</Expires>" sEnv = sEnv & " </Timestamp>" sEnv = sEnv & " <Locale>jp</Locale>" sEnv = sEnv & " </soap:Header>" sEnv = sEnv & " <soap:Body>" sEnv = sEnv & " <" & LOGIN_API_NAME & ">" sEnv = sEnv & " <parameters>" sEnv = sEnv & " <" & Para(0,0) & ">" & Para(0,1) & "</" & Para(0,0) & ">" sEnv = sEnv & " <" & Para(1,0) & ">" & Para(1,1) & "</" & Para(1,0) & ">" sEnv = sEnv & " </parameters>" sEnv = sEnv & " </" & LOGIN_API_NAME & ">" sEnv = sEnv & " </soap:Body>" sEnv = sEnv & "</soap:Envelope>" '作成したリクエストをPOSTします。 objHTTP.Open "POST", Full_URL, False objHTTP.send sEnv If objHTTP.Status <> 200 Then GaroonAPI_Login = False Set objHTTP = Nothing Set ReqXML = Nothing Exit Function End If 'XML解析用のオブジェクトを生成します。 Set objXML = CreateObject("MSXML2.DOMdocument") 'レスポンスをxmlで読み込みます。 objXML.LoadXML(objHTTP.ResponseText) For Each elm In objXML.getElementsByTagName("returns") '目的の値を取得します。 rtnVal = elm.getElementsByTagName("status")(0).text Next If rtnVal = "Login" Then GaroonAPI_Login = True Else GaroonAPI_Login = False End If Set objHTTP = Nothing Set objXML = Nothing End Function
如何でしょうか?
上記のコードは洗練とは程遠い泥くさい書き方ではありますが、このようにXMLをべた書きするほうが可読性は高いと思います。
念のため、上記のXMLべた書き側のコードを部分的に補足説明いたします。
ガルーンのSOAP APIでは、APIの機能の分類によって配置されているURLが異なります。
ログインやログアウトなどのAPIはこのURLを指定して呼び出します。
パラメーターを配列に入れていますが、このログインのAPI実行だけで言えば、わざわざ配列化する必要性は無いです。
必要によって普通の変数に書き変えてください。
ここはこのAPIを呼び出す際のタイムスタンプを指定します。
上記のコードではガルーンのデベロッパーサイトのリクエスト例と同じ値を指定していますが、本来は適切な値を指定するべきです。
「Created」ではこのAPIを呼び出す際のシステム日時、「Expires」では、有効期限を指定するので、なるべく短い未来の時間を指定したほうが良いです。
APIがレスポンスとして返してくるXMLを解析し、要素名「status」に”Login”が入っていたらログイン成功としています。
ログアウト用APIを実行するサンプルプログラム
当項では、ガルーンをログアウトするAPIを実行するサンプルプログラムを紹介します。
尚、以降のサンプルプログラムでは、可読性の観点から、XMLベタ書きのコードで進めていきます。
XMLをベタ書きするにあたって、XMLの生成処理を一部関数化します。
特にXMLのヘッダー部分はガルーンの別のSOAP APIでも共通なので、以降のXML生成処理では常に呼び出すようにしていきます。
'リクエストで使用するXMLヘッダーの文字列を生成して返します。 Function Get_CreateXML_Header(API_Name) Dim sEnv sEnv = "<?xml version=""1.0"" encoding=""UTF-8""?>" sEnv = sEnv & "<soap:Envelope xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">" sEnv = sEnv & " <soap:Header>" sEnv = sEnv & " <Action>" & API_Name & "</Action>" sEnv = sEnv & " <Security>" sEnv = sEnv & " <UsernameToken>" sEnv = sEnv & " <Username>" & LOGIN_USERNAME & "</Username>" sEnv = sEnv & " <Password>" & LOGIN_PASSWORD & "</Password>" sEnv = sEnv & " </UsernameToken>" sEnv = sEnv & " </Security>" sEnv = sEnv & " <Timestamp>" sEnv = sEnv & " <Created>2010-08-12T14:45:00Z</Created>" sEnv = sEnv & " <Expires>2037-08-12T14:45:00Z</Expires>" sEnv = sEnv & " </Timestamp>" sEnv = sEnv & " <Locale>jp</Locale>" sEnv = sEnv & " </soap:Header>" Get_CreateXML_Header = sEnv End Function 'UtilLogoutを使用してガルーンをログアウトしてその実行結果を返します。 '引数1:無し '戻り値:真偽 ※ログアウト成功:True 失敗:False Function GaroonAPI_Logout() Dim objHTTP Dim Full_URL Dim sEnv Dim ReqXML Dim objXML Dim retCd Dim elm Dim rtnVal GaroonAPI_Logout = False Full_URL = BASE_URL & LOGIN_API_DIR Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP") 'リクエスト用xml文字列を生成します。※パラメーター無し sEnv = sEnv & " <soap:Body>" sEnv = sEnv & " <UtilLogout>" sEnv = sEnv & " </UtilLogout>" sEnv = sEnv & " </soap:Body>" sEnv = sEnv & "</soap:Envelope>" ReqXML = Get_CreateXML_Header("UtilLogout") & vbcrlf & sEnv 'リクエストをPOSTします。 objHTTP.Open "POST", Full_URL, False objHTTP.send ReqXML retCd = objHTTP.Status If retCd <> 200 Then 'httpレスポンスコードが異常な場合はFalseを返します。 Set objHTTP = Nothing Set ReqXML = Nothing Exit Function End If 'XML解析用のオブジェクトを生成します。 Set objXML = CreateObject("MSXML2.DOMdocument") 'レスポンスをxmlで読み込みます。 objXML.LoadXML(objHTTP.ResponseText) For Each elm In objXML.getElementsByTagName("returns") '目的の値を取得します。 rtnVal = elm.getElementsByTagName("status")(0).text Next If rtnVal = "Logout" Then GaroonAPI_Logout = True End If Set objHTTP = Nothing Set ReqXML = Nothing End Function
上記のコードはFunctionプロシージャとして独立しているので、VBSやVBAから適当に呼び出してもらえばそのまま動くと思います。
後編について
今回の記事では、ガルーンのSOAP APIをVBScriptで呼び出す際のサンプルプログラムの紹介と、APIを今後使いこなせるように、基礎的なAPIの知識を紹介しました。
これで、ガルーンに対してウェブの通信を使用したログインとログアウトはできるようになったはずです。
次回の記事では、ユーザーアカウントの登録処理に関するサンプルプログラムを紹介していこうと思います。
↓後編はこちらのリンクから
今回も長々と読んでいただきましてありがとうございました。
また次回もよろしくお願いいたします。