javascripttutorialsoap-api

JavaScript から SOAP API を呼ぶ時に、チームへ XML を背負わせない方法

SOAPless Team7 min read

JavaScript チームが本当に知りたいのは、「SOAP をどう好きになるか」ではなく、「どこまでを自前で持つべきか」です。

JavaScript の世界は JSON と REST を前提に回っています。その中で SOAP を扱う必要が出ると、たいてい XML の構築、名前空間、WSDL、Fault の扱いで急に速度が落ちます。

この記事では、Node.js とブラウザの両方を前提に、SOAP を直接呼ぶ方法だけでなく、「その責務をどこまでチームに持たせるべきか」という観点で整理します。

方法 1: node-soap ライブラリを使う(Node.js)

Node.js 環境で最も広く使われている SOAP クライアントは node-soap です。WSDL を自動解析してクライアントを生成してくれるため、XML を手動で構築する手間が省けます。

npm install soap
const soap = require('soap');

const wsdlUrl = 'https://example.com/service?wsdl';

async function callSoapService() {
  // WSDL からクライアントを自動生成
  const client = await soap.createClientAsync(wsdlUrl);

  // オペレーション呼び出し(JavaScript オブジェクトを渡す)
  const args = {
    userId: 42,
    includeProfile: true
  };

  const [result] = await client.GetUserAsync(args);
  console.log('ユーザー情報:', result);
}

callSoapService().catch(console.error);

node-soap は WSDL のスキーマから型情報を読み取り、JavaScript オブジェクトを SOAP XML エンベロープに自動変換します。レスポンスも JavaScript オブジェクトにパースされるため、XML を直接扱う量は減ります。

ただし、チーム全体の問題はまだ残ります。WSDL の癖、認証、Fault、ブラウザとの境界の問題は消えません。

WS-Security 認証の設定

多くの SOAP サービスは WS-Security を要求します。node-soap にはビルトインのサポートがあります。

const soap = require('soap');

async function callWithAuth() {
  const client = await soap.createClientAsync(wsdlUrl);

  // WS-Security ヘッダーを追加
  const wsSecurity = new soap.WSSecurity('username', 'password', {
    hasNonce: true,
    hasTimeStamp: true
  });
  client.setSecurity(wsSecurity);

  const [result] = await client.GetUserAsync({ userId: 42 });
  return result;
}

方法 2: fetch で直接 XML を送信する

ライブラリを使わず、生の XML を fetch で送信する方法です。ブラウザと Node.js(18 以降)の両方で動作します。

async function callSoapDirect() {
  const soapEnvelope = `<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:tns="http://example.com/services">
  <soap:Body>
    <tns:GetUserRequest>
      <tns:userId>42</tns:userId>
    </tns:GetUserRequest>
  </soap:Body>
</soap:Envelope>`;

  const response = await fetch('https://example.com/service', {
    method: 'POST',
    headers: {
      'Content-Type': 'text/xml; charset=utf-8',
      'SOAPAction': '"http://example.com/services/GetUser"'
    },
    body: soapEnvelope
  });

  const xmlText = await response.text();
  console.log('レスポンス XML:', xmlText);

  // XML をパースする
  const parser = new DOMParser();
  const doc = parser.parseFromString(xmlText, 'text/xml');
  const userName = doc.getElementsByTagName('tns:userName')[0]?.textContent;
  console.log('ユーザー名:', userName);
}

この方法はシンプルですが、以下の問題があります。

  • XML エンベロープを手動で構築する必要がある
  • 名前空間の管理が煩雑
  • レスポンスの XML パースが面倒
  • WSDL の変更に追従するのが困難

方法 3: axios + xml2js の組み合わせ(Node.js)

axios で HTTP リクエストを送り、xml2js でレスポンスをパースする方法です。

npm install axios xml2js
const axios = require('axios');
const { parseStringPromise } = require('xml2js');

async function callSoapWithAxios() {
  const soapEnvelope = `<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:tns="http://example.com/services">
  <soap:Body>
    <tns:GetUserRequest>
      <tns:userId>42</tns:userId>
    </tns:GetUserRequest>
  </soap:Body>
</soap:Envelope>`;

  const response = await axios.post('https://example.com/service', soapEnvelope, {
    headers: {
      'Content-Type': 'text/xml; charset=utf-8',
      'SOAPAction': '"http://example.com/services/GetUser"'
    }
  });

  // XML を JavaScript オブジェクトに変換
  const parsed = await parseStringPromise(response.data, {
    explicitArray: false,
    ignoreAttrs: true,
    tagNameProcessors: [name => name.replace(/^.*:/, '')]
  });

  const body = parsed.Envelope.Body;
  console.log('パース結果:', JSON.stringify(body, null, 2));
}

tagNameProcessors で名前空間プレフィックスを除去しているのがポイントです。これをしないと soap:Body のようなキー名になり、JavaScript での扱いが不便になります。

各方法の比較

観点node-soapfetch + DOMParseraxios + xml2js
WSDL 自動解析ありなしなし
XML 手動構築不要必要必要
WS-Securityビルトイン手動実装手動実装
ブラウザ対応不可可能不可
型安全性部分的なしなし
保守性

よくあるトラブルと対処法

SOAPAction ヘッダーの指定忘れ

多くの SOAP サービスは SOAPAction HTTP ヘッダーを要求します。値が間違っているとリクエストがルーティングされず、エラーになります。

// WSDL から正しい SOAPAction を確認
// <operation> タグの soapAction 属性に記載されている
headers: {
  'SOAPAction': '"http://example.com/services/GetUser"'  // 引用符を含む
}

CORS エラー(ブラウザ)

ブラウザから直接 SOAP サービスを呼ぶと、ほぼ確実に CORS エラーが発生します。SOAP サービスは通常 CORS ヘッダーを返しません。サーバーサイドのプロキシを経由するか、Node.js のバックエンドで SOAP 呼び出しを行ってください。

XML エンコーディングの問題

日本語を含むリクエストでは、UTF-8 エンコーディングの指定が重要です。Content-Type ヘッダーに charset=utf-8 を必ず含めましょう。

もっと簡単な方法

ここまで見てきたように、JavaScript から SOAP API を呼び出すのは REST API と比べてかなりの手間がかかります。XML の構築、名前空間の管理、レスポンスのパース、WS-Security の実装と、本来のビジネスロジック以外の作業が多くなりがちです。

SOAP の XML 変換を自動化したいなら、SOAPless が 30 秒で REST エンドポイントを生成します。WSDL の URL を入力するだけで、fetchaxios で JSON を送受信できる REST API が手に入ります。XML を一切触ることなく、JavaScript から SOAP サービスを利用できるようになります。

// SOAPless 経由なら、標準的な REST 呼び出しだけ
const response = await fetch('https://soapless.miravy.com/api/v1/your-account-id/your-service/GetUser', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ userId: 42 })
});

const data = await response.json();
console.log('ユーザー情報:', data);

XML エンベロープの構築もパースも不要。JavaScript の開発体験のまま SOAP サービスを利用できます。