はじめに
仕事で他サービスのAPIを呼び出す際に、SOAP通信をおこなう必要があったのでそのノウハウを記事にしました。
使用したライブラリは node-soap です。
基本的には、README を参考に実装しています。
Node.js で SOAP 通信をおこなう
SOAP client の生成
import * as soap from 'soap';
/***** 中略 *****/
const client = await soap.createClientAsync(wsdlPath, options);
公式だと、以下の形でクライアントを生成しています。
私が利用したAPIでは、定められたメソッドを順番に呼び出す必要があったので非同期処理で実装をおこなっています。
// README
soap.createClient(url, function(err, client) {
client.MyFunction(args, function(err, result) {
console.log(result);
});
});
// README
soap.createClientAsync(url).then((client) => {
return client.MyFunctionAsync(args);
}).then((result) => {
console.log(result);
});
API のメソッドを呼び出す
const fisrtResult = await client.MyFunctionAsync(firstArgs, firstOptions, firstHeader);
const secondResult = await client.MyFunction2Async(secondArgs, secondOptions, secondHeader);
client.methodAsync
を利用した場合、返却される結果は [result, rawResponse, soapHeader, rawRequest] の形の配列となります。
取得結果を利用する場合は firstResult[0]
、送信したタグを確認したい場合は firstResult[3]
を参照します。
SOAP の際のパラメータについて
node-soap
では様々なパラメータをセットして通信をおこなうことができます。
soap.createClientAsync
でセットされる options
は、WSDL に関する設定をすることができます。
useEmptyTag
などがその一例となります。
const wsdlOptions = {
useEmptyTag: true,
}
複数の namespace を使用する場合にはオプションを以下のようにすることで実現できる、との情報を見つけましたが、筆者の環境では動きませんでした。
namespace の設定は後述します。
const wsdlOptions = {
overrideRootElement: {
namespace: 'xmlns:tns',
xmlnsAttributes: [{
name: 'xmlns:ns2',
value: "http://example.com/xxx/xxx",
}, {
name: 'xmlns:ns3',
value: "http://example.com/xxx/xxx",
}]
},
}
次に、メソッドに渡すパラメータについて確認します。
client.MyFunctionAsync
には firstArgs
でパラメータを、 firstHeader
で Cookie 情報を渡しました。今回、 firstOptions
は使用しませんでした。
(* Cookie は利用した API の要件です。)
パラメータは、オブジェクト形式で渡します。
const Args1 = {
tag: 'value',
}
const Args2 = {
tag: {
attributes: {
key: 'key',
value: 'value',
},
},
}
上記のオブジェクトを引数として渡すと、 Args1
, Args2
はそれぞれ、下記の形になります。
// Args1
<tag>value</tag>
// Args2
<tag key="key" value="value"></tag>
タグの値を配列にすることで、親タグ内に複数の同じタグを並行して設定することができます。
const Params = [
{
key: 'key1',
value: 'value1',
},
{
key: 'key2',
value: 'value2',
},
];
<parent>
<children key="key1" value="value1"></children>
<children key="key2" value="value2"></children>
</parent>
namespace を拡張する
client
を生成した後に、下記の処理をおこなうことで namespace を拡張できます。
client.wsdl.definitions.xmlns.ns2 = 'http://example.com/xxx/xxx';
client.wsdl.definitions.xmlns.ns3 = 'http://example.com/xxx/xxx';
client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap()
タグを namespace から引用したい場合、下記の形にすれば利用できました。
const Args1 = {
"ns2:tag": 'value',
}
const Args2 = {
"ns3:tag": {
attributes: {
key: 'key',
value: 'value',
},
},
}
おわりに
SOAP 自体の知識が乏しかったため、実装に難航しました。
また、 node-soap
自体は Cookie を利用したセッションの管理には対応していないようなので、その部分は別に実装することになりました。
レスポンスのヘッダーは client.lastResponseHeaders['set-cookie']
で取得することができます。
不明点、不備などがありましたらコメントいただけますと幸いです。