Excel VBAだけで社内WebAPIと連携するシステムを開発する時に知っておくべきHTTP通信の実装手順とエラー回避法

Excel VBAで社内WebAPIとHTTP通信を連携させるシステム開発の実装手順とエラー回避法を解説するイメージ プログラミング言語

Excel VBAで社内WebAPIと連携するシステムを構築する際、多くの開発者が最初に直面するのがHTTP通信の実装です。
VBAはモダンな言語ではありませんが、WinHTTPやMSXML2などのCOMオブジェクトを活用すれば、RESTful APIとのやり取りを十分に実現できます

この記事では、実際の現場で発生しやすい以下の課題に焦点を当て、具体的な解決策を解説します。

  • 認証トークンの付与方法とセキュアな管理
  • JSON形式のリクエストボディの構築とパース処理
  • タイムアウトやステータスコードに起因する通信エラーの切り分け
  • プロキシ環境下での接続失敗の回避

特に、社内システムではAD認証やクライアント証明書が絡むケースも少なくありません。
そうした特殊な要件に対しても、VBA側でどのように対処すべきか、エラーハンドリングを含めた実装手順を段階的に説明していきます。

コードの記述に入る前に、まずHTTP通信の基本フローと、VBA特有の制約を整理しておきましょう。

  1. VBAでWebAPI連携を実装する前に知っておくべきHTTP通信の基礎知識
    1. HTTPリクエストの構成要素
    2. 主要なHTTPメソッドの使い分け
    3. レスポンスの構造とステータスコード
    4. VBA特有の制約と事前確認事項
  2. WinHTTPとMSXML2の違いと、社内API連携に最適なライブラリの選定基準
    1. 両ライブラリの基本的な特性
    2. 機能比較と選定基準
    3. 実装時の具体的な違い
    4. 社内環境における推奨の選定フロー
  3. 基本認証からBearerトークンまで:API認証の実装パターンとセキュリティ対策
    1. よく使われる認証方式の比較
    2. AD認証やクライアント証明書が必要な社内APIへの接続方法
    3. アクセストークンの安全な管理とリフレッシュ処理の実装
  4. リクエストの組み立て方:URLエンコード、ヘッダー設定、JSONボディの構築手順
    1. URLパラメータの正しいエンコード方法と文字化けの防止
    2. JSON形式のリクエストボディをVBAで動的に生成するテクニック
  5. レスポンスの処理:ステータスコードの判定とJSONパースの実装
    1. HTTPステータスコードに応じたエラーハンドリングの設計
    2. ScriptControlを使わずにJSONをパースする方法と制約への対処
  6. 通信エラーの切り分けと回避:タイムアウト、プロキシ、SSL証明書の問題解決
    1. 接続タイムアウトと送信タイムアウトの適切な設定値と再試行ロジック
    2. 社内プロキシ環境下での接続失敗の原因と回避策
    3. 自己署名証明書や中間証明書の問題を解決するSSL設定
  7. 実装の鉄則:エラーハンドリングとログ出力で運用を安定させる設計思想
    1. On Error GoToの限界と、API連携に最適な構造化エラーハンドリング
    2. 通信ログの出力設計と、トラブルシューティングを効率化するデバッグ手法
  8. 実務で役立つ:社内WebAPI連携システムの実装を成功させる総まとめ
    1. 実装の全体フローと各段階の要点
    2. よく陥る落とし穴と最終的な注意点

VBAでWebAPI連携を実装する前に知っておくべきHTTP通信の基礎知識

Excel VBAで社内WebAPIと連携する際のHTTP通信の基礎概念を解説するイメージ

WebAPI連携を実装する際、まず押さえておくべきはHTTPというプロトコルの本質です。
HTTPは、クライアントとサーバー間でリクエストとレスポンスという一対のやり取りを行うステートレスな通信規約です。
つまり、クライアントが「何を」「どのように」要求するかを明確に定義したリクエストを送信し、サーバーはその要求に対して適切なレスポンスを返すという構造になっています。
VBAから社内WebAPIを呼び出すということは、この構造に従って正確なリクエストを組み立て、返却されたレスポンスを適切に解釈する作業であると認識しておく必要があります。

HTTPリクエストの構成要素

HTTPリクエストは大きく分けて3つの要素で構成されます。
リクエストラインヘッダーボディです。
リクエストラインには、使用するHTTPメソッド(GETやPOSTなど)、アクセスするURL、そして使用するHTTPのバージョンが含まれます。
ヘッダーには、リクエストのメタ情報が記述されます。
例えば、送信するデータの形式を示すContent-Typeや、認証情報を含むAuthorizationなどが代表的です。
ボディは、POSTやPUTといったメソッドでサーバーにデータを送信する際に使用されます。
JSON形式のデータを含める場合、ヘッダーでContent-Type: application/jsonを指定し、ボディにJSON文字列を格納するという流れが一般的です。

主要なHTTPメソッドの使い分け

WebAPIを利用する際、どのHTTPメソッドを選択するかは重要な設計判断です。
以下に、社内システムでよく使われるメソッドとその役割を整理します。

メソッド 役割 ボディの有無 冪等性
GET リソースの取得 原則なし あり
POST リソースの作成 あり なし
PUT リソースの完全更新 あり あり
PATCH リソースの部分更新 あり なし
DELETE リソースの削除 あり(場合による) あり

冪等性というのは、同じリクエストを何度実行しても結果が変わらない性質のことです。
GETやPUT、DELETEは冪等ですが、POSTはそうではありません。
VBAで社内APIを連携する際、この性質を理解しておくことで、再試行ロジックの設計や、通信エラー発生時の挙動をより論理的に判断できます。

レスポンスの構造とステータスコード

サーバーから返されるHTTPレスポンスも、リクエストと同様にステータスラインヘッダーボディの3要素で構成されます。
ステータスラインに含まれるステータスコードは、リクエストの成否を数値で示す重要な指標です。
200番台は成功、400番台はクライアント側のエラー、500番台はサーバー側のエラーを表します。
VBAでの実装では、まずこのステータスコードを確認し、正常終了か異常終了かを判定するのが鉄則です。
特に、社内APIでは認証エラー(401)や権限不足(403)、リソース不在(404)など、400番台のエラーが頻出します。
これらを適切にハンドリングできるよう、あらかじめAPI仕様書で定義されているステータスコードの一覧を把握しておくべきです。

VBA特有の制約と事前確認事項

VBAでHTTP通信を行う際、モダンな言語とは異なるいくつかの制約があります。
まず、ネイティブなJSONサポートがないという点が大きな障壁となります。
PythonやJavaScriptであれば標準ライブラリでJSONのパースや生成が可能ですが、VBAでは独自の処理が必要です。
また、非同期通信が標準でサポートされていないため、APIのレスポンスが返ってくるまで処理がブロックされるという特性があります。
長時間のAPI呼び出しを行う場合は、Excelがフリーズしたように見えるため、ユーザーエクスペリエンスを考慮した設計が求められます。

さらに、社内環境ではプロキシサーバーの存在や、NTLM認証やクライアント証明書といった高度な認証要件が課されることがあります。
これらは、単にHTTPリクエストを送信するだけでは解決せず、ライブラリの設定やOSレベルの構成変更が必要になるケースもあります。
そのため、実装に入る前に、社内のネットワーク構成やセキュリティポリシーを把握しておくことが、後のトラブルを大幅に減らすことになります。

以上の基礎知識を踏まえた上で、次の章からは具体的なVBAでの実装手順に移っていきます。

WinHTTPとMSXML2の違いと、社内API連携に最適なライブラリの選定基準

VBAのHTTP通信ライブラリWinHTTPとMSXML2を比較するイメージ

VBAからHTTP通信を行う際、利用できるCOMオブジェクトとして主にWinHTTPMSXML2.XMLHTTPの2つが挙げられます。
どちらもWindowsに標準搭載されており、追加インストールなしで使用できるという利点があります。
しかし、これらは内部的なアーキテクチャや対応する機能に違いがあり、社内API連携という特定の要件に対して、どちらを選ぶかは慎重に検討すべきです。

両ライブラリの基本的な特性

まず、それぞれのライブラリがどのような層で動作するかを理解することが重要です。
MSXML2.XMLHTTPは、Internet ExplorerのXMLHTTPコンポーネントをベースとしており、WinINetというWindowsのインターネット通信APIを利用しています。
そのため、IEのプロキシ設定やセキュリティゾーンの設定の影響を受けるという特徴があります。
一方、WinHTTPは、WinINetとは独立したHTTPスタックを持っており、サーバー向けの通信に最適化されています。
プロキシの自動検出や、NTLM認証の扱い方などで挙動が異なります。

実務上の大きな違いとして、MSXML2はユーザーのプロキシ設定を自動的に引き継ぐのに対し、WinHTTPはシステム全体のWinHTTPプロキシ設定、あるいはコード内での明示的な設定に依存するという点があります。
社内ネットワークでは、個別のプロキシ設定が行われているケースが少なくありません。
このような環境では、MSXML2の方が設定が楽に済む一方、セキュリティポリシーによってはWinHTTPの方が厳格な制御が可能です。

機能比較と選定基準

以下に、社内API連携の観点から重要な機能を比較した表を示します。

比較項目 MSXML2.XMLHTTP WinHTTP
プロキシ自動検出 IEの設定に依存 システム設定またはコード指定
NTLM認証 自動的に試行される 明示的な設定が必要な場合あり
クライアント証明書 対応 対応(設定方法が異なる)
タイムアウト制御 簡易的 詳細に設定可能
非同期通信 対応 対応
レスポンスストリーミング 非対応 対応

この表を見ると、高度な認証や細かいタイムアウト制御が必要な社内システムではWinHTTPが有利であることが読み取れます。
特に、クライアント証明書を用いた相互認証が必要なAPIでは、WinHTTPの方が柔軟に証明書ストアを指定できるケースが多いです。
逆に、単純なGETリクエストで社内のプロキシ設定がIEに依存している場合は、MSXML2の方が実装工数を抑えられます。

実装時の具体的な違い

コード上での違いも押さえておきましょう。
MSXML2.XMLHTTPの場合、以下のようにオブジェクトを生成します。

Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP")

WinHTTPの場合は以下のようになります。

Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

リクエストの送信方法自体は、どちらもOpenSetRequestHeaderSendという流れで大きく変わりません。
しかし、WinHTTPではSetProxyメソッドを使ってプロキシを明示的に指定できたり、SetTimeoutsメソッドで解決、接続、送信、受信の各フェーズごとにタイムアウトを設定できる点が大きな違いです。
社内APIで大きなファイルを送受信する場合、送信タイムアウトを長めに設定するといった調整がWinHTTPでは容易に行えます。

社内環境における推奨の選定フロー

では、実際のプロジェクトでどちらを選べばよいのでしょうか。
以下の観点で判断することをお勧めします。

  • プロキシ設定がIEに一元管理されており、複雑な認証が不要な場合はMSXML2を選択する
  • NTLM認証やクライアント証明書、細かいタイムアウト制御が必要な場合はWinHTTPを選択する
  • セキュリティポリシーでIEの設定変更が制限されている環境ではWinHTTPを選択する
  • レスポンスのサイズが大きく、ストリーミング処理が必要な場合はWinHTTPを選択する

なお、両方のライブラリを同一のVBAプロジェクト内で混在させることは技術的に可能ですが、保守性の観点からは避けるべきです。
プロジェクト全体で一貫したHTTP通信層を設計し、必要に応じて共通のラッパー関数を作成してライブラリの差異を抽象化するのが、中長期的に見て賢明なアプローチです。

本記事では、社内API連携でよく求められる高度な認証や細かい制御を想定し、WinHTTPを中心に解説を進めていきます。
ただし、MSXML2固有の挙動に言及が必要な箇所では、適宜補足していきます。

基本認証からBearerトークンまで:API認証の実装パターンとセキュリティ対策

VBAでのAPI認証方式の実装とセキュリティ対策を解説するイメージ

社内WebAPIを利用する際、認証は避けて通れない関門です。
認証方式を誤って選択すると、セキュリティホールを生むだけでなく、運用後に変更が困難な技術的負債を抱えることになります。
ここでは、VBAからのAPI連携で頻出する認証パターンを、セキュリティの観点から整理します。

よく使われる認証方式の比較

社内APIでよく使われる認証方式には、Basic認証Bearerトークン(OAuth 2.0やJWT)APIキー、そしてNTLMやKerberosを用いたWindows統合認証があります。
それぞれの特徴とVBA実装時の注意点を以下にまとめます。

認証方式 セキュリティレベル VBA実装の難易度 主な用途
Basic認証 低(Base64エンコードのみ) レガシーAPI、開発環境
Bearerトークン 高(HTTPS必須) モダンなREST API
APIキー 社内簡易API
Windows統合認証 Active Directory連携

Basic認証は、ユーザー名とパスワードをBase64エンコードした文字列をAuthorizationヘッダーに付与するだけのシンプルな方式です。
しかし、Base64は暗号化ではなくエンコードであるという点を忘れてはなりません。
平文に近い状態で送信されるため、HTTPSでの通信が絶対条件です。
社内ネットワークであっても、平文のBasic認証を許容するべきではありません。

Bearerトークンは、モダンなAPIで最も一般的な方式です。
アクセストークンをAuthorization: Bearer <トークン>という形式でヘッダーに設定します。
トークン自体には有効期限が設定されるため、Basic認証に比べてセキュリティが高く、漏洩した場合の影響を時間的に限定できます。

AD認証やクライアント証明書が必要な社内APIへの接続方法

社内システムでは、Active Directory(AD)によるシングルサインオンや、クライアント証明書を用いた相互認証が要求されるケースが少なくありません。
これらは、一般のパブリックAPIとは異なる実装アプローチが必要です。

WinHTTPを使用する場合、NTLM認証やNegotiate認証(Kerberos)に対応するには、SetAutoLogonPolicyメソッドの設定が重要です。
デフォルトでは、現在ログオンしているユーザーの資格情報を自動的に利用する動作になっていますが、社内ポリシーによっては明示的な設定が必要になることがあります。

Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetAutoLogonPolicy 0 ' 0: AutoLogonPolicy_Always

クライアント証明書を使用する場合は、SetClientCertificateメソッドで証明書ストア内の証明書を指定します。
社内環境では、個人の証明書ストア(CURRENT_USER\MY)や、マシン全体の証明書ストア(LOCAL_MACHINE\MY)に展開された証明書が使われます。
証明書の選択には、拇印(Thumbprint)やサブジェクト名を指定する方法がありますが、拇印を使う方が一意性が保証され、誤選択のリスクが低いです。

http.SetClientCertificate "LOCAL_MACHINE\MY\1234567890ABCDEF..."

なお、クライアント証明書を使う際の落とし穴として、中間証明書の信頼チェーンが不完全なケースが挙げられます。
サーバー側が中間証明書を適切に送信しない場合、VBA側でSSLハンドシェイクが失敗します。
このような場合は、サーバー側の設定を修正するか、クライアント側で中間証明書を明示的に信頼する必要があります。

アクセストークンの安全な管理とリフレッシュ処理の実装

Bearerトークンを使用する場合、トークンの管理方法がセキュリティの要となります。
トークンをVBAコード内にハードコーディングすることは、絶対に避けるべきです。
ソースコードは比較的容易に抽出可能であり、トークンの有効期限が長い場合、重大な情報漏洩リスクを伴います。

推奨されるアプローチは、以下の2つです。

  • 環境変数やレジストリに暗号化して保存し、実行時に復号して読み込む
  • リフレッシュトークンを利用し、アクセストークンの有効期限を短く設定する

リフレッシュトークンの実装は、OAuth 2.0の仕組みを理解している前提で行う必要があります。
初回認証時にアクセストークンとリフレッシュトークンの両方を取得し、アクセストークンの有効期限が切れた際に、リフレッシュトークンを用いて新しいアクセストークンを取得するという流れです。

Private Function RefreshAccessToken(refreshToken As String) As String
    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    http.Open "POST", "https://api.company.local/oauth/token", False
    http.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"

    Dim body As String
    body = "grant_type=refresh_token&refresh_token=" & refreshToken

    http.Send body

    If http.Status = 200 Then
        ' レスポンスから新しいアクセストークンを抽出
        RefreshAccessToken = ParseTokenFromJson(http.ResponseText)
    Else
        Err.Raise vbObjectError + 1, , "トークン更新に失敗しました: " & http.Status
    End If
End Function

トークンの有効期限管理についても、単純に「取得してから30分」という時間ベースの管理ではなく、APIレスポンスに含まれるexpires_inや、JWTのペイロードに含まれるexpクレームを解析して正確に判定する方が堅牢です。
JWTのペイロードはBase64UrlエンコードされたJSONであり、VBAでデコードしてexpの値を取得することは可能です。

認証の実装は、セキュリティと利便性のトレードオフを常に意識する必要があります。
社内APIであっても、トークンの漏洩や資格情報の不適切な管理は、組織全体のセキュリティインシデントに発展するリスクを孕んでいます。
実装に入る前に、社内のセキュリティポリシーと照らし合わせ、最適な認証方式を選定してください。

リクエストの組み立て方:URLエンコード、ヘッダー設定、JSONボディの構築手順

VBAでHTTPリクエストのURLエンコードやヘッダー、JSONボディを構築する手順を解説するイメージ

HTTPリクエストを正確に組み立てることは、API連携の成否を左右する根本的な作業です。
特にVBAのようなレガシーな環境では、モダンな言語が隠蔽してくれるエンコーディングや文字列処理の詳細を、開発者自身が意識的に制御する必要があります。
ここでは、リクエスト構築の3要素であるURL、ヘッダー、ボディのそれぞれについて、実装上の注意点を解説します。

URLパラメータの正しいエンコード方法と文字化けの防止

URLにクエリパラメータを含める場合、RFC 3986で定められたルールに従ったエンコードが必須です。
日本語やスペース、記号などの予約語をそのままURLに含めると、サーバー側で正しく解釈されず、404エラーや意図しない検索結果が返されるケースが生じます。

VBAにはネイティブなURLエンコード関数が存在しないため、独自の実装が必要です。
一般的なアプローチとして、ADODB.Streamを利用してUTF-8バイト配列に変換し、各バイトを%XX形式に変換する方法があります。
以下に、実用的なエンコード関数を示します。

Private Function UrlEncode(ByVal str As String) As String
    Dim i As Long
    Dim buf() As Byte
    Dim result As String

    buf = StrConv(str, vbFromUnicode)

    For i = 0 To UBound(buf)
        Select Case buf(i)
            Case 48 To 57, 65 To 90, 97 To 122, 45, 46, 95, 126
                result = result & Chr(buf(i))
            Case 32
                result = result & "+"
            Case Else
                result = result & "%" & Right("0" & Hex(buf(i)), 2)
        End Select
    Next i

    UrlEncode = result
End Function

この関数では、英数字とハイフン、ドット、アンダースコア、チルダはエンコードせず、その他の文字はUTF-8バイト列として%エンコードします。
スペースは+に変換していますが、厳密にはRFC 3986では%20が推奨されるため、API仕様に応じて調整してください。

なお、Shift_JISとUTF-8の混在は社内システムで特に問題になりやすいポイントです。
サーバー側がUTF-8を期待しているのに、VBA側がShift_JISでエンコードすると、文字化けが発生します。
エンコード前に必ずサーバーの文字コード仕様を確認し、統一したエンコーディングで通信するよう徹底してください。

JSON形式のリクエストボディをVBAで動的に生成するテクニック

モダンなWebAPIでは、リクエストボディにJSONを含めることが標準です。
しかし、VBAにはJSONシリアライザが存在しないため、文字列連結でJSONを組み立てるか、Dictionaryオブジェクトを介して構造化するかの選択が必要です。

単純なJSONであれば、文字列連結でも十分ですが、ネストが深くなったり、配列が含まれる構造になると、可読性と保守性が著しく低下します
以下に、DictionaryとCollectionを組み合わせて構造化JSONを生成するアプローチを示します。

Private Function BuildJsonBody() As String
    Dim root As Object
    Set root = CreateObject("Scripting.Dictionary")

    root.Add "user_id", "U001"
    root.Add "department", "開発部"

    Dim items As Object
    Set items = CreateObject("System.Collections.ArrayList")

    Dim item1 As Object
    Set item1 = CreateObject("Scripting.Dictionary")
    item1.Add "product_code", "P100"
    item1.Add "quantity", 2
    items.Add item1

    Dim item2 As Object
    Set item2 = CreateObject("Scripting.Dictionary")
    item2.Add "product_code", "P200"
    item2.Add "quantity", 1
    items.Add item2

    root.Add "order_items", items.ToArray()

    BuildJsonBody = JsonEncode(root)
End Function

この例では、Scripting.Dictionaryでキー・バリューペアを管理し、ArrayListで可変長の配列を構築しています。
最終的にJsonEncodeという独自関数でJSON文字列に変換します。
実際のJsonEncode関数は、Dictionaryのキーと値を再帰的に走査し、文字列値にはダブルクォートを付与、数値はそのまま、配列は角括弧で囲むといった処理を行います。

動的に値を変更する場合は、DictionaryのItemプロパティを利用して値を上書きすればよく、テンプレート的なJSON文字列を用意するよりも、型安全性と拡張性の観点から有利です。
特に、ユーザー入力やセル値をJSONに組み込む場合、文字列連結ではエスケープ漏れによるJSON構文エラーが発生しやすく、Dictionaryベースのアプローチであれば、値のエスケープ処理を一箇所に集約できます。

リクエストの組み立ては、見た目ほど単純な作業ではありません。
エンコーディングの不一致や、JSON構文の些細なミスが、原因不明のAPIエラーを生み出すことがあります。
各要素をモジュール化し、単体テスト可能な構造にすることで、後のデバッグ工数を大幅に削減できます。

レスポンスの処理:ステータスコードの判定とJSONパースの実装

VBAでHTTPレスポンスのステータスコードを判定しJSONを解析するイメージ

APIからのレスポンスを正しく処理することは、リクエスト送信と同等に重要です。
特にVBAのような型が緩やかな言語では、レスポンスの構造を前提にしたコードを書くと、予期しないデータ形式で実行時エラーが発生しやすくなります。
ここでは、ステータスコードの判定とJSONパースの実装について、堅牢なアプローチを解説します。

HTTPステータスコードに応じたエラーハンドリングの設計

APIレスポンスを受け取った直後に行うべきは、ステータスコードの確認です。
WinHTTPのStatusプロパティで取得できる数値は、リクエストの成否を端的に示します。
しかし、単純に200番台かどうかを判定するだけでは不十分で、各ステータスコードに応じた分岐処理を設計することで、エラーの原因を迅速に特定できます。

以下に、社内APIで頻出するステータスコードと、推奨するハンドリング方針をまとめます。

ステータスコード 意味 推奨する対処
200 OK 正常にレスポンスボディを処理する
400 Bad Request リクエストパラメータの見直し、バリデーション強化
401 Unauthorized 認証トークンの再取得、資格情報の確認
403 Forbidden アクセス権限の確認、別エンドポイントの検討
404 Not Found URLパスの確認、リソースIDの存在確認
500 Internal Server Error サーバー側ログの確認、リトライ処理の検討
503 Service Unavailable 一時的な停止と判断し、指数バックオフで再試行

401エラーが返された場合、トークンの有効期限切れが最も多い原因です。
この場合、リフレッシュトークンを用いて新しいアクセストークンを取得し、同じリクエストを再送信するという自動リカバリロジックを組み込むと、ユーザーの操作を中断させずに済みます。
ただし、無限ループを防ぐため、再試行回数には上限を設ける必要があります。

Private Function SendRequestWithRetry(url As String, method As String, body As String) As String
    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    Dim retryCount As Integer
    retryCount = 0

    Do While retryCount < 3
        http.Open method, url, False
        http.SetRequestHeader "Authorization", "Bearer " & GetAccessToken()

        If body <> "" Then
            http.SetRequestHeader "Content-Type", "application/json"
            http.Send body
        Else
            http.Send
        End If

        Select Case http.Status
            Case 200
                SendRequestWithRetry = http.ResponseText
                Exit Function
            Case 401
                If retryCount < 2 Then
                    RefreshAccessToken
                    retryCount = retryCount + 1
                Else
                    Err.Raise vbObjectError + 1, , "認証に失敗しました"
                End If
            Case 500, 502, 503
                retryCount = retryCount + 1
                Application.Wait Now + TimeValue("00:00:02")
            Case Else
                Err.Raise vbObjectError + 2, , "HTTPエラー: " & http.Status & " " & http.StatusText
        End Select
    Loop
End Function

この実装では、401エラー時にトークンをリフレッシュして再試行し、500番台のサーバーエラー時には2秒の待機を挟んで再試行しています。
Select Caseによる分岐は、後からステータスコードの対処を追加しやすく、保守性に優れています。

ScriptControlを使わずにJSONをパースする方法と制約への対処

レスポンスボディがJSON形式の場合、VBAでその内容を取り出す必要があります。
かつてはScriptControlオブジェクトを用いてJavaScriptのJSON.parseを呼び出す方法が主流でしたが、64ビット版OfficeではScriptControlが利用できないという重大な制約があります。
さらに、社内環境ではセキュリティポリシーによりスクリプト実行が制限されるケースもあり、依存を減らす方向で実装するのが賢明です。

代替となるアプローチは、正規表現と文字列操作を組み合わせたパース、あるいはJSONを再帰的に走査する独自パーサの実装です。
以下に、比較的シンプルなキー・バリューペアを抽出する正規表現ベースの実装を示します。

Private Function GetJsonValue(json As String, key As String) As String
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")

    regex.Global = False
    regex.IgnoreCase = True
    regex.Pattern = """" & key & """\s*:\s*""([^""]*)"""

    Dim matches As Object
    Set matches = regex.Execute(json)

    If matches.Count > 0 Then
        GetJsonValue = matches(0).SubMatches(0)
    Else
        regex.Pattern = """" & key & """\s*:\s*([0-9]+)"
        Set matches = regex.Execute(json)

        If matches.Count > 0 Then
            GetJsonValue = matches(0).SubMatches(0)
        End If
    End If
End Function

この関数は、文字列値と数値値の両方に対応していますが、ネストしたJSONや配列には対応していません
より複雑なJSONを扱う場合は、再帰的にオブジェクトを構築するパーサが必要になります。
実装工数を考慮すると、必要なフィールドのみを正規表現で抽出するという必要最小限のアプローチを取るか、あるいは外部のJSONパーサライブラリを参照登録するかの判断が求められます。

なお、レスポンスが非常に大きい場合、文字列全体をメモリに展開するとパフォーマンスが低下します。
WinHTTPのResponseBodyプロパティはバイト配列を返すため、ストリーミング的に処理することも検討できますが、JSONパースの観点からは実装が複雑になります。
社内APIであれば、通常はレスポンスサイズが数MBを超えることは少ないため、文字列ベースの処理で十分なケースがほとんどです。

レスポンス処理の設計は、エラーの早期発見と、想定外のデータへの耐性を両立させることがポイントです。
ステータスコードの網羅的なハンドリングと、JSONパースの段階的な堅牢化を進めることで、運用後のトラブルを最小限に抑えることができます。

通信エラーの切り分けと回避:タイムアウト、プロキシ、SSL証明書の問題解決

VBAのHTTP通信で発生するタイムアウトやプロキシ、SSL証明書のエラーを解決するイメージ

社内WebAPIとの連携では、コードが正しく書けていても、ネットワーク環境に起因するエラーが頻発します。
これらのエラーは、APIサーバー自体の問題とは切り分けて診断する必要があり、エラーメッセージの文言だけでは原因が特定しにくいケースがほとんどです。
ここでは、タイムアウト、プロキシ、SSL証明書という3つの観点から、通信エラーの切り分け方と回避策を体系的に解説します。

接続タイムアウトと送信タイムアウトの適切な設定値と再試行ロジック

WinHTTPでは、SetTimeoutsメソッドを使って4種類のタイムアウトを個別に設定できます。
デフォルト値はいずれも30秒または60秒ですが、社内ネットワークの状況やAPIの処理特性に応じて、これらを適切に調整することが重要です。

Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

' 単位はミリ秒
http.SetTimeouts 5000, 10000, 30000, 30000

各パラメータの意味は以下の通りです。

パラメータ 意味 推奨設定
第1引数 名前解決タイムアウト 5秒程度
第2引数 接続タイムアウト 10秒程度
第3引数 送信タイムアウト データサイズに応じて調整
第4引数 受信タイムアウト サーバー処理時間に応じて調整

名前解決が5秒以上かかる環境は、DNS設定に問題がある可能性が高いため、長く設定しても意味がありません。
一方、送信タイムアウトは、大きなファイルをPOSTする場合には短すぎると通信中断を招きます。
社内APIでよくある帳票データの一括登録などでは、送信タイムアウトを60秒以上に延長するのが現実的です。

タイムアウトが発生した際の再試行ロジックは、単純な固定間隔の再試行ではなく、指数バックオフを採用すると効果的です。
1回目は2秒待機、2回目は4秒、3回目は8秒と、待機時間を指数関数的に増やすことで、一時的なサーバー過負荷が回復する時間を与えつつ、過度なリクエスト集中を防ぎます。

社内プロキシ環境下での接続失敗の原因と回避策

社内ネットワークでは、インターネット接続と同様に、APIサーバーへのアクセスもプロキシ経由となることが一般的です。
WinHTTPの場合、プロキシ設定が不適切だと、接続そのものが確立できず、エラーコード12002(タイムアウト)や12007(サーバー名の解決に失敗)が返されます。

まず確認すべきは、システム全体のWinHTTPプロキシ設定です。
コマンドプロンプトで以下を実行し、プロキシが設定されているか確認します。

netsh winhttp show proxy

プロキシが未設定、あるいは誤った設定になっている場合、コード内で明示的に指定する方法があります。

http.SetProxy 2, "proxy.company.local:8080", "*.company.local"

第1引数の2は、指定したプロキシを使用する設定です。
第3引数のバイパスリストには、社内ドメインを指定して、社内APIへのアクセスがプロキシを経由しないようにすることも可能です。
ただし、NTLM認証を要求するプロキシの場合、WinHTTPは自動的に現在のユーザー資格情報を利用しますが、MSXML2の場合はIEのプロキシ設定と連動するため、挙動が異なる点に注意が必要です。

プロキシ関連のエラーが疑われる場合、まずブラウザやcurlなどの別ツールで同じURLにアクセスできるか確認し、VBA固有の問題なのか、ネットワーク環境全体の問題なのかを切り分けることが、迅速な解決につながります。

自己署名証明書や中間証明書の問題を解決するSSL設定

社内システムでは、コストや運用の簡便性から、自己署名証明書や社内CAが発行した証明書が使用されることがあります。
これらの証明書は、一般的なパブリックCAの証明書と異なり、OSの信頼ストアに登録されていない場合、SSLハンドシェイクでエラーが発生します。

WinHTTPの場合、エラーコード12029や12030がSSL関連のエラーを示します。
自己署名証明書を一時的に無視する設定は以下のように行えますが、本番環境では推奨されません

http.Option(4) = 256 ' WinHttpRequestOption_SslErrorIgnoreFlags

この設定は、証明書の有効期限切れや信頼性の問題をすべて無視します。
セキュリティリスクが高いため、開発・テスト環境でのみ使用し、本番環境では正しい証明書を信頼ストアにインストールする対応を行ってください。

中間証明書の問題は、サーバー側が中間CAの証明書を適切に送信していない場合に発生します。
この場合、クライアント側で中間証明書を手動で信頼ストアに登録するか、サーバー側の設定を修正する必要があります。
社内APIの管理者と連携し、SSL Labsなどの診断ツールでサーバーの証明書チェーンを確認することで、問題の所在を特定できます。

通信エラーの切り分けは、エラーコードの意味を正しく理解し、ネットワーク層とアプリケーション層を分離して考えることが重要です。
タイムアウト、プロキシ、SSLという3つの観点を順に確認していくことで、ほとんどの通信問題は論理的に解決に導くことができます。

実装の鉄則:エラーハンドリングとログ出力で運用を安定させる設計思想

VBAのWebAPI連携システムをエラーハンドリングとログで安定運用する設計思想のイメージ

システム開発において、正常系の実装だけを考えていると、運用開始後に予期しない障害に翻弄されることになります。
特に外部APIとの連携では、ネットワークの揺らぎやサーバーの一時的な停止は避けられないため、異常系をどれだけ堅牢に設計するかが、システムの信頼性を左右します
ここでは、VBAにおけるエラーハンドリングの最適化と、効果的なログ設計について解説します。

On Error GoToの限界と、API連携に最適な構造化エラーハンドリング

VBAの標準的なエラーハンドリングはOn Error GoToですが、この方式には根本的な限界があります。
エラーが発生した際に指定したラベルにジャンプするため、エラー発生箇所からの文脈が失われやすく、どの処理段階で失敗したのかを追跡するのが困難です。
API連携のように多層の処理(認証、リクエスト構築、送信、レスポンス解析)が連続する場合、この限界は顕著になります。

より構造化されたアプローチとして、各処理段階で成否を判定し、失敗時には即座に制御を返す早期リターンのパターンを推奨します。
以下に、API連携関数での実装例を示します。

Private Function CallApiSafely(endpoint As String, payload As String) As ApiResult
    Dim result As ApiResult
    Set result = New ApiResult

    Dim http As Object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    On Error GoTo Cleanup

    http.Open "POST", endpoint, False

    If Not SetAuthentication(http) Then
        result.Status = "AUTH_FAILED"
        GoTo Cleanup
    End If

    http.SetRequestHeader "Content-Type", "application/json"
    http.Send payload

    If http.Status <> 200 Then
        result.Status = "HTTP_ERROR"
        result.HttpStatus = http.Status
        result.ErrorBody = http.ResponseText
        GoTo Cleanup
    End If

    result.Status = "SUCCESS"
    result.Body = http.ResponseText

Cleanup:
    If Err.Number <> 0 Then
        result.Status = "EXCEPTION"
        result.ErrorMessage = Err.Description
        Err.Clear
    End If

    Set CallApiSafely = result
End Function

この実装では、認証設定、HTTP送信、ステータス判定の各段階で失敗を検出し、即座にCleanupラベルへ遷移します。
ApiResultという専用のクラスを定義することで、呼び出し元では結果オブジェクトのプロパティを確認するだけで、どの段階で何が失敗したのかを正確に把握できます
GoToの使用は避けられませんが、ジャンプ先を単一のクリーンアップ処理に集約することで、スパゲッティコード化を防ぎます。

さらに、エラー情報を単なる文字列ではなく、構造化したオブジェクトとして扱うことで、呼び出し元での分岐処理が明確になります。
例えば、HTTP_ERRORの場合はリトライ、AUTH_FAILEDの場合はユーザーに資格情報の再入力を促す、といった対応が型安全に記述できます。

通信ログの出力設計と、トラブルシューティングを効率化するデバッグ手法

ログは、運用時のトラブルシューティングにおいて唯一無二の手がかりです。
しかし、ログを残さないことと、すべてを残すことのいずれも問題です。
ログがないと障害の原因特定に時間がかかり、逆に過剰なログはファイルサイズの肥大化や機密情報の漏洩リスクを招きます。

API連携において最低限記録すべき情報は、以下の4つです。

  • リクエスト時刻とエンドポイントURL
  • HTTPメソッドとステータスコード
  • エラー発生時のエラーメッセージとレスポンスボディの要約
  • 処理の所要時間

以下に、ログ出力の実装例を示します。

Private Sub WriteApiLog(level As String, message As String, context As Dictionary)
    Dim logPath As String
    logPath = Environ("APPDATA") & "\MyApp\api_log.txt"

    Dim fileNum As Integer
    fileNum = FreeFile

    Open logPath For Append As #fileNum

    Dim timestamp As String
    timestamp = Format(Now, "yyyy-mm-dd hh:nn:ss")

    Dim contextStr As String
    If Not context Is Nothing Then
        Dim key As Variant
        For Each key In context.Keys
            contextStr = contextStr & key & "=" & context(key) & "; "
        Next key
    End If

    Print #fileNum, timestamp & " [" & level & "] " & message & " | " & contextStr
    Close #fileNum
End Sub

このサブルーチンでは、Dictionaryオブジェクトを使ってコンテキスト情報を構造化し、一貫したフォーマットでログを出力します。
ログファイルの保存場所は、ユーザーのAPPDATAフォルダ以下に設定することで、書き込み権限の問題を回避できます。

デバッグ時には、一時的にリクエストボディとレスポンスボディの全文をログに残す設定を切り替えられるようにすると効果的です。
ただし、本番環境では個人情報や認証情報が含まれる可能性があるため、ボディのログ出力は原則として無効化し、エラー発生時のみ要約を記録するという設計が望ましいです。

また、Excel上で動作するVBAの特性上、メッセージボックスによるデバッグは避けるべきです。
バッチ処理中にメッセージボックスが表示されると、処理が停止してしまい、自動運用の目的を損ないます。
すべての情報はファイルログまたは即時ウィンドウ(Debug.Print)に出力し、必要に応じてログビューアを別途構築する方が、運用の自動化と監視の両立が図れます。

エラーハンドリングとログ出力は、システムの「安全装置」に相当します。
正常系の実装に没頭しすぎてこれらを後回しにすると、運用後の修正コストが指数関数的に増大します。
設計の初期段階から、異常系をどう扱うかを明確にし、ログ設計を含めた一貫した方針を定めることが、長期的な安定運用への近道です。

実務で役立つ:社内WebAPI連携システムの実装を成功させる総まとめ

Excel VBAでの社内WebAPI連携システム開発の成功ポイントを総まとめするイメージ

本記事では、Excel VBAから社内WebAPIと連携するシステムを構築する際に必要なHTTP通信の実装手順と、エラー回避のための設計思想を解説してきました。
ここまでの内容を総括し、実務に即した形で最終的な指針を整理します。

実装の全体フローと各段階の要点

社内WebAPI連携システムの開発は、以下の段階を順に踏むことで、無駄な試行錯誤を最小限に抑えることができます。

まず事前調査の段階では、API仕様書の確認と同時に、社内のネットワーク構成とセキュリティポリシーの把握が不可欠です。
認証方式がBasic認証なのかBearerトークンなのか、あるいはAD統合認証やクライアント証明書が必要なのかを、実装に入る前に明確にしておく必要があります。
また、プロキシサーバーの有無や、SSL証明書の発行元も確認しておくことで、後の通信エラーの切り分けが劇的に容易になります。

次にライブラリ選定の段階では、MSXML2とWinHTTPのいずれを採用するかを判断します。
単純なリクエストでIEのプロキシ設定をそのまま利用できるのであればMSXML2で十分ですが、NTLM認証やクライアント証明書、詳細なタイムアウト制御が必要な場合はWinHTTPを選択すべきです。
プロジェクト全体で一貫した方針を定め、ラッパー関数を作成してライブラリの差異を抽象化することで、将来の変更にも柔軟に対応できます。

リクエスト構築の段階では、URLエンコードの徹底と、JSONボディの正確な構築が求められます。
特に日本語を含むパラメータはUTF-8でエンコードし、サーバー側の文字コード仕様と整合性を取る必要があります。
JSONの生成には、単純な文字列連結ではなく、Dictionaryベースのアプローチを採用することで、エスケープ漏れや構文エラーを未然に防ぐことができます。

レスポンス処理の段階では、ステータスコードの網羅的な判定を行い、200番台以外の場合には適切なエラーハンドリングを発動させます。
401エラー時の自動トークンリフレッシュや、500番台エラー時の指数バックオフによる再試行など、リカバリロジックを事前に設計しておくことで、一時的な障害からの自動復旧を実現できます。

運用保守の段階では、構造化されたエラーハンドリングと適切なログ出力が、障害対応の速度を左右します。
エラー情報を型安全なオブジェクトとして扱い、ログには時刻、ステータスコード、処理時間、エラー要約を記録することで、運用担当者が原因を特定するための手がかりを確保します。

よく陥る落とし穴と最終的な注意点

実務で特に注意すべき点を、以下に最終確認として列挙します。

  • 認証トークンのハードコーディングは、セキュリティインシデントの直接的な原因となるため、絶対に避ける
  • タイムアウト設定はデフォルト値のまま運用せず、APIの処理特性に応じて調整する
  • 自己署名証明書の無視設定は、開発環境でのみ使用し、本番環境では正しい証明書を信頼ストアに登録する
  • メッセージボックスによるデバッグは、バッチ処理の自動化を阻害するため、ファイルログまたはDebug.Printに置き換える
  • レスポンスのJSONパースは、必要なフィールドに絞り込み、過度に複雑な汎用パーサを無理に実装しない

VBAはモダンな開発環境ではありませんが、WinHTTPやCOMオブジェクトを適切に活用し、堅牢なエラーハンドリングを施すことで、十分に実用的なAPI連携システムを構築できます
重要なのは、言語の制約を認識した上で、その制約の中で最善の設計を行うことです。

社内システムの現場では、既存のExcel資産を活かしつつ、モダンなAPI基盤と連携させるニーズが増えています。
本記事で解説した手法を基盤として、各社の環境に応じたカスタマイズを進めていただければ、安定した運用が長く続くシステムが実現できることでしょう。
最後に、実装に入る前の設計段階での十分な検討と、段階的なテストの重要性を再度強調して、本記事を締めくくりたいと思います。

コメント

タイトルとURLをコピーしました