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-soap | fetch + DOMParser | axios + 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 を入力するだけで、fetch や axios で 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 サービスを利用できます。