Access VBAからWeb API(REST)を呼ぶ方法と注意点
MSXML2.XMLHTTP.6.0かWinHTTPでHTTPリクエストを送る基本と、VBAに標準JSONパーサがない実情、ScriptControlのVBScript廃止リスク、APIキーのコード直書き禁止など実務上の注意点を解説します。
結論:MSXML2.XMLHTTP か WinHTTP を使う。JSONは自前で処理する覚悟が必要
Access VBAから外部のREST APIを呼ぶ方法は確立されています。Windowsに標準で入っているMSXML2.XMLHTTP.6.0かWinHttp.WinHttpRequest.5.1のどちらかをCreateObjectで生成し、Open→Send→responseTextの流れでHTTPリクエストを送る形です。
ただし、ここで多くの開発者が立ち止まるのがJSONの扱いです。VBAにはJSONの標準パーサがありません。かつてよく使われたScriptControl(MSScriptControl.ScriptControl)は、64bit版Officeでは動作しないという根本的な制約があります。現時点では代替として「自前パース」か「外部ライブラリ(VBA-JSON等)」を選ぶのが実情です。
また、APIキーやアクセストークンをVBAコードに直書きするのは絶対に避けてください。accdbファイルをメールで送ったとたんに認証情報が漏れます。この記事では実務で使える構成と、運用上の注意点を整理します。
2種類のHTTPオブジェクトとその使い分け
VBAから使えるHTTPオブジェクトは主に2つです。
| オブジェクト | ProgID | ネットワークスタック | 特徴 |
|---|---|---|---|
MSXML2.XMLHTTP.6.0 | Msxml2.XMLHTTP.6.0 | WinINet(IEと共通) | IEのプロキシ設定を自動的に引き継ぐ。デスクトップアプリの定番 |
WinHttp.WinHttpRequest.5.1 | WinHttp.WinHttpRequest.5.1 | WinHTTP(独立スタック) | IE/WinINetのユーザープロキシ設定を自動継承しない。サービス・バックグラウンド実行向き。タイムアウト制御が明示的 |
Microsoft公式ドキュメントによると、MSXML2.XMLHTTP.6.0はIXMLHTTPRequestインターフェースを実装し、open/send/setRequestHeader/responseTextなどのメソッド・プロパティを持ちます(msxml6.dll実装)。WinHttp.WinHttpRequest.5.1はWinHTTPのCOMオートメーションコンポーネントで、Open/Send/SetRequestHeader/ResponseText/SetTimeoutsなどを持ちます(winhttp.dll実装)。
社内ネットワークでプロキシを使っている環境では、MSXML2.XMLHTTPの方が設定の手間が少ない傾向があります。一方、バックグラウンドで動かすVBAやサーバー上で実行するスクリプトにはWinHTTPが向くとMicrosoftは説明しています。どちらを選んでも基本的なリクエストの書き方はほぼ同じです。
GETリクエストの基本コード例
まず最もシンプルなGETリクエストの例です。MSXML2.XMLHTTP.6.0を使います。
Sub GetApiData()
On Error GoTo ErrHandler
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP.6.0")
Dim url As String
url = "https://api.example.com/items?limit=10"
' 第3引数がFalse = 同期(処理が完了するまで待つ)
http.Open "GET", url, False
http.setRequestHeader "Accept", "application/json"
http.Send
If http.Status = 200 Then
Dim responseText As String
responseText = http.responseText
' responseTextにJSONが入っている
Debug.Print responseText
Else
MsgBox "APIエラー: " & http.Status & " " & http.statusText
End If
Set http = Nothing
Exit Sub
ErrHandler:
MsgBox "通信エラー: " & Err.Number & vbCrLf & Err.Description
Set http = Nothing
End SubOpenの第3引数をFalseにすると同期実行になります。APIのレスポンスが遅い場合、Accessが固まったように見えるので注意が必要です。http.StatusでHTTPステータスコードを確認し、200以外のケース(401 Unauthorized、429 Too Many Requestsなど)を必ずハンドリングしてください。
認証情報の扱い方(コードへの直書き禁止)
APIを使う際に必ずつきまとうのが認証の問題です。APIキーやBearer TokenをVBAのコードに直接書くのは危険です。accdbファイルごとコピーされたり、メールで送信されたりした時点で認証情報が外部に出ます。
コードへの直書きを避けるための現実的な代替手段を整理します。ただし以下の方法はいずれも「コードからの分離」であり、暗号化による保護ではありません。より厳格な機密性が必要な場合は、認証処理を中間サーバーに委譲する構成を検討してください。
| 方法 | 概要 | 注意点 |
|---|---|---|
| Accessテーブルに保存 | 「システム設定」テーブルにAPIキーを格納し、起動時に読み込む | accdbにアクセスできる人には平文で見える。DBパスワードをかけても開かれれば読める |
| Windowsレジストリ(SaveSetting) | SaveSetting/GetSettingでレジストリに保存する(VBA標準関数) | HKEY_CURRENT_USER配下にユーザー単位で平文保存。同じWindowsユーザーなら誰でも読める |
| 環境変数 | Windowsの環境変数に入れ、Environ("API_KEY")で取得 | 管理者が端末ごとに設定する。値は平文で保存されている |
Bearerトークンが必要なAPIでは、http.setRequestHeader "Authorization", "Bearer " & apiKeyのように送ります。OAuth 2.0のような複数ステップ認証フローをVBAで実装するのは手間が大きく、Access VBAの得意領域ではありません。そうした場合はPower Automateや中間サーバーに認証を任せる構成も検討してください。AccessとPower Automateの連携についても参考にしてください。
JSONの扱い方とScriptControlが使えない理由
REST APIのレスポンスはほぼJSON形式です。VBAにはJSONを扱う標準機能がなく、ここがAccess VBA連携の最大の難所になります。
かつてはScriptControl(MSScriptControl.ScriptControl)でLanguage="JScript"と指定してJavaScriptエンジンにJSONをパースさせる手法が使われていました。しかしMSScriptControlは32bitコンポーネントであり、64bit版Officeでは動作しません(Microsoftのフォーラムでも確認されている既知の制約です)。現在の多くの環境が64bit版Officeを使っている点を考えると、新規実装での採用は避けた方が無難です。VBScript廃止との関係についてはVBScript廃止とAccess VBAへの影響も参照してください。
2025年11月8日時点で現実的なJSONパースの選択肢は次の3つです。
| 手法 | 概要 | メリット | デメリット |
|---|---|---|---|
| 自前の文字列パース | InStr/Mid/Splitで必要な値を切り出す | 外部依存なし | 構造が複雑なJSONには限界。ネストや配列で壊れやすい |
| VBA-JSON(外部ライブラリ) | Tim Hall氏のVBA-JSONをモジュールとしてインポート | 本格的なJSONをパース可能 | モジュールをaccdbに取り込む必要がある。ライセンス確認を |
| ScriptControl | Language="JScript"でJavaScriptエンジンを介してパース | コードが短い | 32bit専用。64bit版Officeでは動作しない |
レスポンスのJSON構造がシンプルで固定されている場合に限り、自前パースを使う選択肢があります。ただし本格的なJSONパーサではなく、想定外の形式では誤動作します。認証・金額・権限に関わる値のパースには使わないでください。以下は「value」キーの文字列値を取り出す最低限の例で、数値・真偽値・ネスト・エスケープが混在する形式には対応していません。
' 簡易パース例(単純な {"value": "abc"} 形式向け)
Function ExtractJsonValue(jsonStr As String, key As String) As String
Dim searchKey As String
searchKey = """" & key & """:"
Dim pos As Long
pos = InStr(jsonStr, searchKey)
If pos = 0 Then Exit Function
Dim startPos As Long
startPos = pos + Len(searchKey)
' 前後の空白とダブルクォートを除去
Do While Mid(jsonStr, startPos, 1) = " " Or Mid(jsonStr, startPos, 1) = """"
startPos = startPos + 1
Loop
Dim endPos As Long
endPos = InStr(startPos, jsonStr, """")
If endPos = 0 Then endPos = InStr(startPos, jsonStr, ",")
If endPos = 0 Then endPos = InStr(startPos, jsonStr, "}")
If endPos = 0 Then Exit Function
ExtractJsonValue = Mid(jsonStr, startPos, endPos - startPos)
End Functionこの手法はネストされた配列や文字列中のエスケープ(\"など)を正しく扱えません。APIのレスポンス構造が複雑な場合は、VBA-JSONのようなライブラリを導入する方が安全です。
タイムアウトとエラー処理の設計
外部APIへの接続はネットワーク状態に左右されます。WinHTTPのSetTimeoutsには4つのタイムアウトがあります。ResolveTimeoutは名前解決(デフォルト0=無期限)、ConnectTimeoutはソケット接続(デフォルト60秒)、SendTimeout/ReceiveTimeoutは個々のパケットの送受信(各デフォルト30秒)です(公式ドキュメントによる)。SendTimeout/ReceiveTimeoutはリクエスト全体の上限ではなく、データが断続的に届く場合は設定値を大きく超えて待機することがあります。MSXML2.XMLHTTPにはSetTimeouts相当の標準設定手段がなく、レスポンス待ちでAccessが固まる場合があります。業務用途ではWinHTTPを選んで明示的に設定する方が管理しやすくなります。
Sub GetWithTimeout()
On Error GoTo ErrHandler
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
' SetTimeoutsは必ずOpenより前に呼ぶ
' 引数: ResolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout (ms)
' デフォルトはConnectTimeout=60000, Send/Receive=30000
http.SetTimeouts 5000, 10000, 30000, 30000
' HTTPSエンドポイントを使う(TLS証明書の検証はWinHTTPが自動で行う)
http.Open "GET", "https://api.example.com/data", False
' WinHTTPは既定でリダイレクトを自動追従し、AuthorizationヘッダーをリダイレクトURLへも転送する
' Bearerトークンを使う場合は自動リダイレクトを無効化して手動で制御する
http.Option(6) = False ' WinHttpRequestOption_EnableRedirects = False(リダイレクト手動制御)
http.SetRequestHeader "Accept", "application/json"
http.SetRequestHeader "Authorization", "Bearer " & GetApiKey()
http.Send
Select Case http.Status
Case 200
Debug.Print http.ResponseText
Case 401
MsgBox "認証エラー(401): APIキーを確認してください"
Case 429
MsgBox "レート制限(429): しばらく待ってから再試行してください"
Case Else
MsgBox "APIエラー: " & http.Status & " " & http.StatusText
End Select
Set http = Nothing
Exit Sub
ErrHandler:
MsgBox "通信エラー: " & Err.Number & vbCrLf & Err.Description
Set http = Nothing
End Sub
' APIキーをコードから分離する例(レジストリ利用)
' ※ SaveSettingはHKEY_CURRENT_USERSoftwareVB and VBA Program Settingsに平文で保存される
' 端末内での分離にはなるが、アクセス権限があれば誰でも読める点に注意
Function GetApiKey() As String
GetApiKey = GetSetting("MyApp", "API", "Key", "")
End Function公式ドキュメントによると、SetTimeoutsの引数は順に「ホスト名解決・接続・送信・受信」のタイムアウト(ミリ秒)で、ConnectTimeoutのデフォルトは60,000ミリ秒(60秒)、SendTimeoutとReceiveTimeoutのデフォルトは30,000ミリ秒(30秒)です。SetTimeoutsはOpenより前に呼ぶ必要があります。
HTTPのステータスコードごとに処理を分けるのは外部API連携では必須です。VBAのエラー処理全般についてはAccess VBAのエラー処理入門で詳しく解説しています。
Access VBAからのAPI連携が向くケースと向かないケース
Access VBAからREST APIを呼ぶ構成はすべての用途に向くわけではありません。
向くのは、すでに運用中のAccess DBに外部データを取り込む処理を追加したい場面です。たとえば、郵便番号APIで住所を補完する、為替レートAPIで最新レートを取得するといった「補助的なAPI呼び出し」は、VBAで十分実用的に動きます。
一方、向かないのは頻繁なリアルタイム通信が必要な用途です。同期リクエスト(Openの第3引数をFalseにした場合)はレスポンスを待つ間Accessがフリーズします。大量のレコードに対して1件ずつAPIを叩くような処理は、レート制限にも引っかかりやすくなります。また、OAuthなど複雑な認証フローをVBAで実装するのは現実的ではありません。そうした用途はPower AutomateやWebアプリ側に処理を移す方が安全です。
現状のAccessに外部連携がどの程度絡んでいるか把握できていない場合、無料の解析可否チェックから整理することもできます。
よくある質問
Q. MSXML2.XMLHTTPとMSXML2.ServerXMLHTTPの違いは?
MSXML2.XMLHTTPはWinINet(Internet Explorerと同じネットワークスタック)を使い、IEのプロキシ設定やCookieを引き継ぎます。MSXML2.ServerXMLHTTPはWinHTTPスタックを使い、デスクトップのIE設定に依存しないため、サービスやサーバー側での実行に向くとMicrosoftは説明しています。デスクトップのAccessで使う場合、プロキシ設定を手動で指定する手間がなければMSXML2.XMLHTTP.6.0の方が手軽です。
Q. ScriptControlを使ったJSONパースは今後も使い続けられますか?
新規実装には向きません。MSScriptControlは32bitコンポーネントであり、64bit版Officeでは動作しないというMicrosoftのフォーラムで確認されている既知の制約があります。JavaScriptのevalを使う手法はセキュリティ上の懸念も指摘されています。既存コードでScriptControlを使っている場合は環境確認(32bit/64bitの区別)と動作テストが先決です。新規実装であればVBA-JSONのようなライブラリか、自前のパース処理を選ぶ方が確実です。
Q. POST/PUTリクエストはどう書きますか?
Openの第1引数を"POST"または"PUT"に変え、setRequestHeaderでContent-Type: application/jsonを指定した上で、Sendの引数にJSONの文字列を渡します。VBAにはJSONを生成する標準関数もないため、送信するJSONは文字列として手動で組み立てるか、VBA-JSONのようなライブラリを使うことになります。文字列を手動で組み立てる場合、ダブルクォート(VBAでは"")だけでなく、バックスラッシュ・改行・タブなどもエスケープが必要です(RFC 8259)。ユーザー入力や変数値をそのまま連結すると不正なJSONや値の注入につながるため、手動連結は固定値のみに絞り、動的な値を含む場合はVBA-JSONのようなライブラリを使う方が安全です。
Q. APIのレスポンスをAccessのテーブルに保存するには?
responseTextで取得した文字列からパースした値を、DAOまたはADOでテーブルに書き込みます。複数件のデータを一括で処理する場合は、ループ内でDAOのRecordsetを使った追加処理をトランザクションで囲む方が安全です。トランザクション処理の実務についてはAccess VBAのトランザクション処理も参照してください。
触れないAccessが「診断できるか」だけ、確かめませんか。
顧客データは送信不要。発注の義務もありません。
約2分・ファイル送信不要・発注義務なし/説明はオンライン・売り込みはしません