ExcelVBAからWebのAPIにアクセスして、天気予報・為替レート・社内システムのデータを自動で取得できたら、どれだけ業務が楽になるか想像してみてください。
実はVBAには標準で WinHttp.WinHttpRequest.5.1 というHTTP通信オブジェクトが搭載されており、外部ライブラリ不要でREST APIを叩けます。
この記事では、WinHTTPの基礎から実践までを一気に解説します。GET・POST・認証ヘッダー・JSONパース・エラーハンドリングまで、すべてコピペ即使えるコードで説明します。
📌 この記事で学べること
- WinHTTPオブジェクトの取得方法(Late Binding / Early Binding)
- GETリクエストでAPIからデータ取得
- POSTリクエストでJSONデータを送信
- APIキー・Bearerトークンをヘッダーに設定する方法
- VBAで外部ライブラリ不要のJSONパース
- タイムアウト設定・ステータスコード別エラーハンドリング
- WinHTTPとは?VBAでHTTP通信できる理由
- 事前準備:参照設定は不要?Late Binding vs Early Binding
- 【基本】GETリクエストでAPIからデータを取得する
- リクエストヘッダーの設定:APIキー・Bearerトークン・Content-Type
- 【実践】POSTリクエストでJSONデータを送信する
- タイムアウト設定:応答待ちで固まらないようにする
- エラーハンドリング:ステータスコード別の対処法
- 【核心】JSONパース:ライブラリ不要でVBAだけで解析する
- 【実践サンプル】為替レートAPIから最新レートを取得してシートに表示
- よくあるエラーと対処法
- まとめ:WinHTTPでVBAをAPI連携の入口にしよう
WinHTTPとは?VBAでHTTP通信できる理由
WinHTTP(Windows HTTP Services)は、Windowsに標準搭載されているHTTP通信ライブラリです。VBAからは WinHttp.WinHttpRequest.5.1 というProgIDで呼び出すことができます。
| 比較項目 | WinHttp.WinHttpRequest.5.1 | MSXML2.XMLHTTP60 | MSXML2.ServerXMLHTTP60 |
|---|---|---|---|
| 推奨度 | ⭐⭐⭐(最推奨) | ⭐⭐ | ⭐⭐ |
| TLS1.2対応 | ✅ 標準対応 | △ 設定必要な場合あり | ✅ |
| プロキシ設定 | ✅ 自動検出 | △ IEの設定を使用 | ✅ 独立設定 |
| 用途 | 汎用REST API | ブラウザ連携系 | サーバーサイド |
| 参照設定 | 不要(Late Binding) | Microsoft XML v6.0 | Microsoft XML v6.0 |
一般的なWebサービスのREST APIを叩く場合、WinHttp.WinHttpRequest.5.1 が最もシンプルで安定しています。本記事はこちらを中心に解説します。
事前準備:参照設定は不要?Late Binding vs Early Binding
VBAでWinHTTPを使う方法は2通りあります。
① Late Binding(参照設定不要・おすすめ)
最初はLate Bindingを使いましょう。参照設定なしで動き、PCの環境差異も少なく済みます。
' Late Binding:参照設定不要・どのPCでも動く
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
② Early Binding(参照設定あり・入力補完が使える)
開発効率を上げたい場合は Early Binding を使います。VBAエディタ(VBE)のメニュー「ツール」→「参照設定」で 「Microsoft WinHTTP Services, version 5.1」 にチェックを入れてください。
' Early Binding:参照設定「Microsoft WinHTTP Services, version 5.1」が必要
' → VBEで ツール > 参照設定 > "Microsoft WinHTTP Services, version 5.1" にチェック
Dim http As WinHttp.WinHttpRequest
Set http = New WinHttp.WinHttpRequest
💡 どちらを選ぶ?
配布するマクロや社内共有ファイルには Late Binding を推奨。自分だけが使う開発中は Early Binding で補完機能を活用するのがベストです。
【基本】GETリクエストでAPIからデータを取得する
まずは最もシンプルなGETリクエストの流れを覚えましょう。下図が基本の3ステップです。
| ステップ | コード | 説明 |
|---|---|---|
| ①オープン | .Open "GET", URL, False | メソッド・URL・同期/非同期を指定 |
| ②送信 | .Send | リクエストを送信 |
| ③レスポンス取得 | .ResponseText | 受け取った文字列(JSON等)を変数に格納 |
サンプルコード:JSONPlaceholderのAPIを叩いてA列に書き込む
練習に最適なのが JSONPlaceholder(無料のダミーAPI)です。https://jsonplaceholder.typicode.com/users にGETすると、ユーザー情報のJSONが返ってきます。
Sub GetAPI_Basic()
'─────────────────────────────────────────
' 【基本】GETリクエストでJSONを取得してA1に表示
'─────────────────────────────────────────
Dim http As Object
Dim sUrl As String
Dim sRes As String
sUrl = "https://jsonplaceholder.typicode.com/users/1"
' ① WinHTTPオブジェクトを生成
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
' ② リクエストを開く(GET, URL, 同期=False)
http.Open "GET", sUrl, False
' ③ 送信
http.Send
' ④ ステータス確認
If http.Status = 200 Then
sRes = http.ResponseText
Sheet1.Range("A1").Value = sRes
MsgBox "取得成功!A1に書き込みました。", vbInformation
Else
MsgBox "エラー: HTTP " & http.Status & vbCrLf & http.StatusText, vbCritical
End If
Set http = Nothing
End Sub
▲ 実行するとA1セルにJSONが丸ごと入ります。次のセクションでJSONをパースして各列に分解する方法を解説します。
リクエストヘッダーの設定:APIキー・Bearerトークン・Content-Type
実際のAPIでは認証ヘッダーが必要なケースがほとんどです。.SetRequestHeader メソッドでヘッダーを追加します。
パターン① APIキーをヘッダーに設定する
Sub GetAPI_WithApiKey()
Dim http As Object
Dim sUrl As String
sUrl = "https://api.example.com/data"
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "GET", sUrl, False
' ─ ヘッダー設定は Open の後・Send の前に行う ─
http.SetRequestHeader "X-API-Key", "ここにAPIキーを貼り付ける"
http.SetRequestHeader "Accept", "application/json"
http.Send
If http.Status = 200 Then
Debug.Print http.ResponseText
Else
MsgBox "HTTP " & http.Status, vbCritical
End If
Set http = Nothing
End Sub
パターン② Bearerトークン(OAuth2)を設定する
Sub GetAPI_WithBearer()
Dim http As Object
Dim sUrl As String
Dim sToken As String
sUrl = "https://api.example.com/resource"
sToken = "eyJhbGci..." ' ←実際のアクセストークンを設定
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "GET", sUrl, False
' Authorization: Bearer {token} の形式で設定
http.SetRequestHeader "Authorization", "Bearer " & sToken
http.SetRequestHeader "Content-Type", "application/json"
http.SetRequestHeader "Accept", "application/json"
http.Send
Debug.Print "Status : " & http.Status
Debug.Print "Response: " & http.ResponseText
Set http = Nothing
End Sub
⚠️ セキュリティ注意
APIキーやトークンをVBAコードに直書きするのは危険です。実運用ではセル参照(例:Sheet2.Range("B1").Value)や入力ダイアログ(InputBox)から取得する設計にしましょう。
【実践】POSTリクエストでJSONデータを送信する
フォーム送信やデータ登録にはPOSTリクエストを使います。ボディ部にJSONを入れて送信するのが現代のREST APIの標準形式です。
Sub PostAPI_JSON()
'─────────────────────────────────────────
' POSTリクエスト:JSONデータを送信して結果を受け取る
'─────────────────────────────────────────
Dim http As Object
Dim sUrl As String
Dim sBody As String
Dim sRes As String
sUrl = "https://jsonplaceholder.typicode.com/posts"
' ── 送信するJSONボディを作成 ──
' ※実際はセルの値から組み立てる(後述のサンプル参照)
sBody = "{""title"":""VBAからの投稿"",""body"":""WinHTTPでPOSTしました"",""userId"":1}"
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "POST", sUrl, False
' ヘッダー:Content-Typeは必須
http.SetRequestHeader "Content-Type", "application/json; charset=UTF-8"
http.SetRequestHeader "Accept", "application/json"
' Send にボディを渡す
http.Send sBody
' ステータス201=作成成功
If http.Status = 200 Or http.Status = 201 Then
sRes = http.ResponseText
MsgBox "POST成功!" & vbCrLf & sRes, vbInformation
Else
MsgBox "エラー: HTTP " & http.Status & vbCrLf & http.StatusText, vbCritical
End If
Set http = Nothing
End Sub
セルの値からJSONボディを組み立てる
実務ではセルの値を使ってJSONを動的に構築します。
Sub PostAPI_FromSheet()
'─────────────────────────────────────────
' シートA2:C2のデータをJSONに変換してPOSTする
' A2=title, B2=body, C2=userId
'─────────────────────────────────────────
Dim http As Object
Dim sUrl As String
Dim sBody As String
Dim sTitle As String
Dim sBodyTxt As String
Dim lUserId As Long
sUrl = "https://jsonplaceholder.typicode.com/posts"
sTitle = Sheet1.Range("A2").Value
sBodyTxt = Sheet1.Range("B2").Value
lUserId = CLng(Sheet1.Range("C2").Value)
' JSON文字列を組み立て(ダブルクォートは "" でエスケープ)
sBody = "{" & _
"""title"":""" & EscapeJson(sTitle) & """," & _
"""body"":""" & EscapeJson(sBodyTxt) & """," & _
"""userId"":" & lUserId & _
"}"
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "POST", sUrl, False
http.SetRequestHeader "Content-Type", "application/json; charset=UTF-8"
http.Send sBody
Debug.Print "Status: " & http.Status
Debug.Print http.ResponseText
Set http = Nothing
End Sub
' ─────────────────────────────────────────────────
' 【ヘルパー関数】JSON用文字列エスケープ
' ダブルクォート・バックスラッシュ・改行コードを処理
' ─────────────────────────────────────────────────
Function EscapeJson(s As String) As String
s = Replace(s, "\", "\\")
s = Replace(s, """", "\""")
s = Replace(s, Chr(13) & Chr(10), "\n")
s = Replace(s, Chr(10), "\n")
s = Replace(s, Chr(13), "\n")
EscapeJson = s
End Function
タイムアウト設定:応答待ちで固まらないようにする
APIサーバーが応答しない場合、.Send のまま永遠に待ち続けてExcelが固まります。.SetTimeouts メソッドで必ず制限時間を設定しましょう。
| 引数 | 意味 | 単位 | 推奨値 |
|---|---|---|---|
| 第1引数 | 名前解決タイムアウト | ミリ秒 | 5000(5秒) |
| 第2引数 | 接続タイムアウト | ミリ秒 | 10000(10秒) |
| 第3引数 | 送信タイムアウト | ミリ秒 | 10000(10秒) |
| 第4引数 | 受信タイムアウト | ミリ秒 | 30000(30秒) |
Sub GetAPI_WithTimeout()
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
' タイムアウト設定(名前解決, 接続, 送信, 受信)単位: ミリ秒
http.SetTimeouts 5000, 10000, 10000, 30000
http.Open "GET", "https://jsonplaceholder.typicode.com/posts/1", False
http.Send
Debug.Print http.ResponseText
Set http = Nothing
End Sub
エラーハンドリング:ステータスコード別の対処法
APIはHTTPステータスコードで結果を通知します。2xx が成功、4xx がクライアントエラー、5xx がサーバーエラーです。
| ステータスコード | 意味 | 対処法 |
|---|---|---|
| 200 OK | 取得成功 | 正常処理 |
| 201 Created | 作成成功(POST) | 正常処理 |
| 400 Bad Request | リクエスト不正 | ボディ・ヘッダーを確認 |
| 401 Unauthorized | 認証失敗 | APIキー・トークンを確認 |
| 403 Forbidden | 権限なし | アクセス権を確認 |
| 404 Not Found | URLが存在しない | エンドポイントURLを確認 |
| 429 Too Many Requests | レート制限 | 待機後リトライ |
| 500 Internal Server Error | サーバー障害 | 時間をおいてリトライ |
Sub GetAPI_ErrorHandling()
'─────────────────────────────────────────
' エラーハンドリング完全版:On Error + ステータス分岐
'─────────────────────────────────────────
Dim http As Object
Dim sUrl As String
sUrl = "https://jsonplaceholder.typicode.com/users/1"
On Error GoTo ErrHandler ' ← ネットワーク接続不可などの実行時エラーを捕捉
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetTimeouts 5000, 10000, 10000, 30000
http.Open "GET", sUrl, False
http.Send
' ── HTTP ステータスコードで分岐 ──
Select Case http.Status
Case 200, 201
' 成功
Debug.Print "成功: " & http.ResponseText
Case 400
MsgBox "400 Bad Request: リクエスト内容を確認してください。", vbCritical
Case 401
MsgBox "401 Unauthorized: APIキー/トークンが無効です。", vbCritical
Case 403
MsgBox "403 Forbidden: アクセス権がありません。", vbCritical
Case 404
MsgBox "404 Not Found: URLが見つかりません。" & vbCrLf & sUrl, vbCritical
Case 429
MsgBox "429 Too Many Requests: リクエスト制限中です。しばらく待ってから再実行してください。", vbExclamation
Case Is >= 500
MsgBox "5xx Server Error (" & http.Status & "): サーバー側の問題です。", vbCritical
Case Else
MsgBox "予期しないステータス: " & http.Status & " " & http.StatusText, vbExclamation
End Select
GoTo Finally
ErrHandler:
' ネットワーク未接続・タイムアウトなどの実行時エラー
MsgBox "通信エラーが発生しました。" & vbCrLf & _
"エラー番号: " & Err.Number & vbCrLf & _
"詳細: " & Err.Description, vbCritical
Finally:
Set http = Nothing
End Sub
【核心】JSONパース:ライブラリ不要でVBAだけで解析する
VBAにはJSONを直接扱う機能がありません。しかしInStr・Mid・Splitを使えば、外部ライブラリなしで主要な値を取り出せます。
方法① 汎用JSONパース関数(InStr + Mid)
シンプルなフラット型JSON(ネストなし)なら以下の関数で対応できます。
' ─────────────────────────────────────────────────
' 【ヘルパー関数】JSON文字列から特定キーの値を取り出す
' 対応形式: {"key":"value"} または {"key":123}
' ─────────────────────────────────────────────────
Function GetJsonValue(sJson As String, sKey As String) As String
Dim lStart As Long
Dim lEnd As Long
Dim sSearch As String
' キー文字列のパターン: "key":
sSearch = """" & sKey & """:"
lStart = InStr(sJson, sSearch)
If lStart = 0 Then
GetJsonValue = ""
Exit Function
End If
' キーの後ろから値を取り出す
lStart = lStart + Len(sSearch)
' 値が文字列(ダブルクォートあり)か数値かを判定
If Mid(sJson, lStart, 1) = """" Then
' 文字列値:次のダブルクォートまで
lStart = lStart + 1
lEnd = InStr(lStart, sJson, """")
GetJsonValue = Mid(sJson, lStart, lEnd - lStart)
Else
' 数値・真偽値:次の , または } まで
lEnd = InStr(lStart, sJson, ",")
If lEnd = 0 Then lEnd = InStr(lStart, sJson, "}")
GetJsonValue = Trim(Mid(sJson, lStart, lEnd - lStart))
End If
End Function
この関数を使って、先ほどのGETレスポンスから各フィールドを取り出してみましょう。
Sub GetAPI_ParseJSON()
'─────────────────────────────────────────
' JSONPlaceholderのユーザー情報をパースしてシートに書き込む
'─────────────────────────────────────────
Dim http As Object
Dim sJson As String
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetTimeouts 5000, 10000, 10000, 30000
http.Open "GET", "https://jsonplaceholder.typicode.com/users/1", False
http.Send
If http.Status <> 200 Then
MsgBox "エラー: " & http.Status, vbCritical
Exit Sub
End If
sJson = http.ResponseText
' ── シートに書き込み ──
With Sheet1
.Range("A1").Value = "ID"
.Range("B1").Value = "名前"
.Range("C1").Value = "ユーザー名"
.Range("D1").Value = "メール"
.Range("E1").Value = "電話"
.Range("A2").Value = GetJsonValue(sJson, "id")
.Range("B2").Value = GetJsonValue(sJson, "name")
.Range("C2").Value = GetJsonValue(sJson, "username")
.Range("D2").Value = GetJsonValue(sJson, "email")
.Range("E2").Value = GetJsonValue(sJson, "phone")
End With
MsgBox "シートに書き込みました!", vbInformation
Set http = Nothing
End Sub
方法② JSON配列をループ処理してシート全行に書き込む
APIが配列形式([{...},{...}])を返す場合は、Splitでオブジェクト単位に分割してループ処理します。
Sub GetAPI_ParseArray()
'─────────────────────────────────────────
' JSONPlaceholderのユーザー一覧(配列)を全行シートに書き込む
'─────────────────────────────────────────
Dim http As Object
Dim sJson As String
Dim aItems As Variant
Dim i As Long
Dim sItem As String
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetTimeouts 5000, 10000, 10000, 30000
http.Open "GET", "https://jsonplaceholder.typicode.com/users", False
http.Send
If http.Status <> 200 Then
MsgBox "エラー: " & http.Status, vbCritical
Exit Sub
End If
sJson = http.ResponseText
' 配列の先頭 [ と末尾 ] を取り除く
sJson = Mid(sJson, 2, Len(sJson) - 2)
' ─ オブジェクト単位に分割(区切り文字: "},{" )─
sJson = Replace(sJson, "},{", "}|{")
aItems = Split(sJson, "|")
' ── ヘッダー行 ──
With Sheet1
.Cells.ClearContents
.Range("A1").Value = "ID"
.Range("B1").Value = "名前"
.Range("C1").Value = "ユーザー名"
.Range("D1").Value = "メール"
' ── データ行ループ ──
For i = 0 To UBound(aItems)
sItem = aItems(i)
.Cells(i + 2, 1).Value = GetJsonValue(sItem, "id")
.Cells(i + 2, 2).Value = GetJsonValue(sItem, "name")
.Cells(i + 2, 3).Value = GetJsonValue(sItem, "username")
.Cells(i + 2, 4).Value = GetJsonValue(sItem, "email")
Next i
End With
MsgBox UBound(aItems) + 1 & " 件のデータを書き込みました!", vbInformation
Set http = Nothing
End Sub
💡 ネストが深いJSONの場合
address.cityのようなネストしたオブジェクトを取り出す場合は、まず外側のオブジェクト文字列を取り出してから再度 GetJsonValue を適用します。複雑なJSONには VBA-JSON ライブラリ(GitHub: VBA-tools/VBA-JSON)の使用も検討してください。
【実践サンプル】為替レートAPIから最新レートを取得してシートに表示
実務に近い例として、無料の為替APIからUSD/JPYレートを取得してシートに書き込むサンプルです。
使用API:Exchange Rate API(無料プラン) ※登録不要・APIキー不要
Sub GetExchangeRate()
'─────────────────────────────────────────
' 【実践】USD→JPY為替レートを取得してA1に書き込む
' 使用API: https://open.er-api.com/v6/latest/USD
'─────────────────────────────────────────
Dim http As Object
Dim sJson As String
Dim sRate As String
Dim sDate As String
On Error GoTo ErrHandler
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetTimeouts 5000, 10000, 10000, 30000
http.Open "GET", "https://open.er-api.com/v6/latest/USD", False
http.SetRequestHeader "Accept", "application/json"
http.Send
If http.Status <> 200 Then
MsgBox "HTTP エラー: " & http.Status, vbCritical
GoTo Finally
End If
sJson = http.ResponseText
' JPYレートを取得("JPY":xxx.xx の形式)
sRate = GetJsonValue(sJson, "JPY")
sDate = GetJsonValue(sJson, "time_last_update_utc")
With Sheet1
.Range("A1").Value = "通貨ペア"
.Range("B1").Value = "レート"
.Range("C1").Value = "更新日時(UTC)"
.Range("A2").Value = "USD/JPY"
.Range("B2").Value = CDbl(sRate)
.Range("B2").NumberFormat = "#,##0.00"
.Range("C2").Value = sDate
End With
MsgBox "USD/JPY = " & sRate & " 円", vbInformation
GoTo Finally
ErrHandler:
MsgBox "エラー: " & Err.Number & " " & Err.Description, vbCritical
Finally:
Set http = Nothing
End Sub
▼ 実行するとシートに下記のように書き込まれます。
| 通貨ペア | レート | 更新日時(UTC) |
|---|---|---|
| USD/JPY | 149.50 | Fri, 01 Mar 2026 00:02:21 +0000 |
よくあるエラーと対処法
| エラー内容 | 原因 | 対処法 |
|---|---|---|
| 実行時エラー -2147012894 | 接続タイムアウト | SetTimeoutsで時間を延ばす。ネットワーク接続を確認 |
| 実行時エラー -2147012891 | 名前解決失敗(URLが間違い) | URLをブラウザで確認。スペルミス注意 |
| HTTP 401 | 認証失敗 | APIキー・Bearerトークンの値・ヘッダー名を再確認 |
| HTTP 400 | リクエスト形式エラー | Content-Type: application/json の設定を確認。JSON文字列の文法チェック |
| 文字化け(レスポンス) | 文字コードの不一致 | ResponseBodyを使いADODB.Streamでデコード(後述) |
| GetJsonValueが空を返す | キー名のスペルミス・大小文字の違い | Debug.Printでsのままの ResponseText を確認してキー名を照合 |
文字化け対策:ADODB.Streamでレスポンスをデコードする
日本語を含むAPIレスポンスで文字化けする場合は ResponseBody プロパティと ADODB.Stream を組み合わせます。
Function GetResponseUtf8(http As Object) As String
'─────────────────────────────────────────
' ResponseBodyをUTF-8としてデコードして返す
' ADODB.StreamはExcel標準で使用可能
'─────────────────────────────────────────
Dim stream As Object
Set stream = CreateObject("ADODB.Stream")
With stream
.Type = 1 ' adTypeBinary
.Open
.Write http.ResponseBody
.Position = 0
.Type = 2 ' adTypeText
.Charset = "UTF-8"
GetResponseUtf8 = .ReadText
.Close
End With
Set stream = Nothing
End Function
' 呼び出し例
Sub Test_Utf8()
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "GET", "https://jsonplaceholder.typicode.com/users/1", False
http.Send
' ResponseText の代わりにこちらを使う
Debug.Print GetResponseUtf8(http)
Set http = Nothing
End Sub
まとめ:WinHTTPでVBAをAPI連携の入口にしよう
✅ この記事で学んだこと
CreateObject("WinHttp.WinHttpRequest.5.1")でHTTP通信オブジェクトを作成Open → SetRequestHeader → Sendの3ステップがREST APIの基本- APIキー・Bearerトークンは
SetRequestHeader "Authorization", "Bearer ..."で設定 SetTimeoutsでタイムアウトを必ず設定してExcelフリーズを防止Select Case http.StatusでHTTPステータスコード別にエラー処理GetJsonValue関数(InStr + Mid)でライブラリ不要のJSONパース- 日本語対応には
ADODB.StreamでUTF-8デコード
WinHTTPを使いこなすと、天気予報・為替・社内API・Microsoft Graph APIなど、あらゆるWebサービスとExcelを繋げることができます。次は認証が必要な本格的なREST APIへの接続や、取得したデータをListObject(テーブル)に自動整形する応用にも挑戦してみましょう。

コメント