「Google Apps Script Execution APIを試してみた。」記事を書いてからひと月経ってしまいましたが、ようやく時間がとれるようになったので、当初の目的であった“VBAからGoogle Apps Script Execution APIを呼び出してみたい!”と思います。
実行するGASコード
呼び出すGoogle Apps Scriptのコードは「Google Apps Script Execution APIを試してみた。」記事のものをそのまま使います。
上記記事でも書いていますが、API呼び出し前に必ず myFunction を実行して動作確認を行ってください。
function getSheetNames(sheetId) { var ss = SpreadsheetApp.openById(sheetId); var sheets = ss.getSheets(); return sheets.map(function(sheet) { return sheet.getName(); }); } function myFunction() { Logger.log(getSheetNames("シートID")); }
下準備
Execution APIを呼び出すに当たり、下記の作業が事前に必要となりますが、作業手順は「Google Apps Script Execution APIを試してみた。」記事をご参照ください。
- 実行可能 API として導入
- API IDの取得
- スコープの取得
- Google Apps Script Execution APIの有効化
- クライアント IDとクライアント シークレットの取得
ただし、“スクリプトにアクセスできるユーザー”は「自分のみ」、
認証情報は OAuth 2.0 クライアント ID → アプリケーションの種類:その他 としてください。
Google Apps Script Execution APIを呼び出すVBAコード
いよいよExecution APIを呼び出すVBAコードです。
API ID、クライアント ID、クライアント シークレット、スコープ、実行するGAS関数名、関数に渡すパラメーターは、それぞれ自分の環境に応じて変更してください。
Option Explicit 'スクリプトにアクセスできるユーザー:自分のみ 'OAuth 2.0 クライアント ID(アプリケーションの種類:その他) 'devMode:false '-------------------------------------------------- '※ 要変更 '-------------------------------------------------- Private Const api_id As String = "API ID" Private Const client_id As String = "クライアント ID" Private Const client_secret As String = "クライアント シークレット" '-------------------------------------------------- Private Const response_type As String = "code" Private Const redirect_uri As String = "urn:ietf:wg:oauth:2.0:oob" Private Const grant_type As String = "authorization_code" Public Sub Sample() Dim auth_code As String Dim access_token As String Dim ret As String Const scope As String = "https://www.googleapis.com/auth/spreadsheets" 'スコープ Const function_name As String = "getSheetNames" '実行するGAS関数名 Const sheet_id As String = "シートID" '初期化 ret = "": auth_code = "": access_token = "" auth_code = GetAuthorizationCode(scope) If Len(Trim(auth_code)) < 1 Then Exit Sub access_token = GetAccessToken(auth_code) If Len(Trim(access_token)) < 1 Then Exit Sub ret = ExecuteGASFunction(access_token, api_id, function_name, sheet_id) Debug.Print "result:" & ret End Sub Private Function ExecuteGASFunction(ByVal access_token As String, _ ByVal api_id As String, _ ByVal function_name As String, _ ByVal parameters As String, _ Optional ByVal dev_mode As String = "false") 'Google Apps Script Execution API呼び出し Dim ret As String Dim url As String Dim json As String Dim dat As Variant Dim d As Object Dim elm As Object ret = "" '初期化 dat = "{'function':'" & function_name & "','parameters':'" & parameters & "','devMode':" & dev_mode & "}" url = "https://script.googleapis.com/v1/scripts/" & api_id & ":run" With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", url, False .SetRequestHeader "Content-Type", "application/json; charset=UTF-8" .SetRequestHeader "Authorization", "Bearer " & access_token .Send dat Select Case .Status Case 200 json = "(" & .responseText & ")" Set d = CreateObject("htmlfile") Set elm = d.createElement("span") elm.setAttribute "id", "result" d.body.appendChild elm d.parentWindow.execScript "document.getElementById('result').innerText=eval(" & json & ").response.result;" ret = elm.innerText End Select End With ExecuteGASFunction = ret End Function Private Function GetAuthorizationCode(ByVal scope As String) As String 'Authorization code取得 Dim ie As Object Dim url As String Dim iptCode As Object Dim auth_code As String Const READYSTATE_COMPLETE = 4 '初期化 Set ie = Nothing Set iptCode = Nothing auth_code = "" url = "https://accounts.google.com/o/oauth2/auth?" & _ "client_id=" & client_id & "&" & _ "response_type=" & response_type & "&" & _ "redirect_uri=" & redirect_uri & "&" & _ "scope=" & EncodeURL(scope) Set ie = CreateObject("InternetExplorer.Application") With ie .Visible = True .AddressBar = False .MenuBar = False .StatusBar = False .Toolbar = False .Width = 600 .Height = 480 .Navigate url While .Busy Or _ .readyState <> READYSTATE_COMPLETE Or _ InStr(LCase(.LocationURL), "https://accounts.google.com/o/oauth2/approval") < 1 DoEvents Wend On Error Resume Next Set iptCode = .document.getElementById("code") On Error GoTo 0 If Not iptCode Is Nothing Then auth_code = iptCode.Value .Navigate "https://accounts.google.com/o/logout" 'ログアウト While .Busy Or .readyState <> READYSTATE_COMPLETE DoEvents Wend .Quit End With GetAuthorizationCode = auth_code End Function Private Function GetAccessToken(ByVal auth_code As String) As String 'Access token取得 Dim access_token As String Dim json As String Dim dat As Variant Dim d As Object Dim elm As Object access_token = "" '初期化 dat = "code=" & auth_code & "&" & _ "client_id=" & client_id & "&" & _ "client_secret=" & client_secret & "&" & _ "redirect_uri=" & redirect_uri & "&" & _ "grant_type=" & grant_type With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", "https://www.googleapis.com/oauth2/v3/token", False .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded;charset=UTF-8" .Send dat If .Status = 200 Then json = .responseText If Len(Trim(json)) > 0 Then json = "(" & .responseText & ")" Set d = CreateObject("htmlfile") Set elm = d.createElement("span") elm.setAttribute "id", "result" d.body.appendChild elm d.parentWindow.execScript "document.getElementById('result').innerText=eval(" & json & ").access_token;" access_token = elm.innerText End If End If End With GetAccessToken = access_token End Function Private Function EncodeURL(ByVal str As String) As String 'URLエンコード Dim d As Object Dim elm As Object str = Replace(str, "\", "\\") str = Replace(str, "'", "\'") Set d = CreateObject("htmlfile") Set elm = d.createElement("span") elm.setAttribute "id", "result" d.body.appendChild elm d.parentWindow.execScript "document.getElementById('result').innerText = encodeURIComponent('" & str & "');" EncodeURL = elm.innerText End Function
上記コードを実行すると、Internet Explorerが表示され、認証とAPIの呼び出しが問題なく行われれば、イミディエイト ウィンドウに指定したスプレッドシートのシート名が表示されます。
これでようやく、VBAからGoogle Apps Script Execution APIを呼び出せることが確認できました。
外部からGAS関数を呼び出せるメリットはとても多く、「Execution API でどこからでも Apps Script コードが実行可能に – Google Developer Japan Blog」にも下記のような記述があります。
Execution API は、Microsoft Office (と VBA) から Apps (と Apps Script) へ「徐々に移行」することを実現する優れたツールです。Office の成熟したワークフローには、VBA で構成されている多くのプロセスが含まれており、さまざまな場所のさまざまな形式のデータを扱う必要があります。特に、多くの要素が移動する自動化されたプロセスでは、1 つの手順でワークロード全体を動かすことが難しくなることもあります。この新しい機能を使用すると、管理可能な規模でデータとプロセスの移行が行えます
上記コメントをしているGoogle Developer ExpertのBruce Mcpherson氏は、正直「ここまでVBAでやるか?」というようなコードをGitHubに載せています(Execution API and Office to Apps migration 参照)。
VBAとGoogle APIの連携をする上で非常に参考になるコードですので、興味がある方は是非ファイルをダウンロードしてコードを見てみてください。
・・・ちなみに、今回のコードを書くに当たり、認証周りでかなりつまづきました。
もしAPIの呼び出しで上手くいかないようであれば、「スクリプトにアクセスできるユーザー」と「devMode」の組み合わせを色々変更してみてください。私はそれで上手くいくようになりました。
勉強になりました。これからGASを勉強しようとしています。
これを参考にPowershellからGASを呼べるようにするところが目標です