Express SOAP Middleware
raw JSON →`express-soap` is an Express middleware designed to streamline the creation of SOAP web services within Node.js applications, leveraging the underlying `node-soap` library. Its current stable version is 1.1.4, published approximately two years ago, suggesting a stable or maintenance release cadence rather than rapid iteration. The primary problem it solves is the inconvenient and potentially problematic integration of `node-soap`'s server listener directly with Express, particularly concerning middleware order and convenience. By providing a standard Express middleware, `express-soap` allows developers to mount SOAP endpoints at specific paths (e.g., `app.use('/soap/path', soap(...))`) in a familiar and predictable manner, addressing a common pain point in `node-soap`'s direct usage. It exposes all `node-soap` options directly, ensuring full compatibility while abstracting away boilerplate involved in setting up SOAP listeners, making it a key differentiator for applications requiring SOAP interoperability with an Express backend.
Common errors
error Error: Cannot find module 'express' or Error: Cannot find module 'soap' ↓
npm install express soap in your project's root directory to install the required peer dependencies. error SOAP Fault: Server Error (or similar generic SOAP fault from client) ↓
res callback with an error object or a valid response under all circumstances. error TypeError: Cannot read properties of undefined (reading 'MyOperation') ↓
services object precisely mirrors the structure of your WSDL, paying close attention to case sensitivity and hierarchy (e.g., services: { ServiceName: { PortName: { MyOperation: ... } } }). Double-check the WSDL for correctness and accessibility. Warnings
breaking `express-soap` has a peer dependency on `express` version `4.x`. While `express` v5 has reached beta, using it with `express-soap` may lead to compatibility issues or unexpected behavior, as the middleware explicitly targets the 4.x API. ↓
breaking As `express-soap` is built upon `node-soap`, any breaking changes in `node-soap`'s API (especially regarding service definitions, options, or callback signatures) can implicitly affect `express-soap` users. `node-soap` has undergone several changes, including how security, WSDL parsing, and asynchronous operations are handled. ↓
gotcha The provided WSDL or XML definition must be valid and accurately reflect the service methods implemented. Small errors in the WSDL (e.g., incorrect namespaces, types, or operation definitions) can lead to the SOAP service failing to initialize or clients receiving SOAP faults. ↓
gotcha SOAP service methods must correctly invoke the `res` callback to send a response back to the client. If `res()` is not called, the SOAP client will typically experience a timeout, leading to an unresponsive service. This applies even for 'one-way' operations where `node-soap` expects a default response. ↓
Install
npm install express-soap yarn add express-soap pnpm add express-soap Imports
- soap wrong
const soap = require('express-soap');correctimport { soap } from 'express-soap'; - soap wrong
import soap from 'express-soap';correctconst { soap } = require('express-soap'); - SoapMiddlewareOptions
import type { SoapMiddlewareOptions } from 'express-soap';
Quickstart
import express from 'express';
import { soap } from 'express-soap';
const app = express();
const PORT = 8000;
// A minimal WSDL definition for demonstration purposes
const myWsdl = `<?xml version="1.0" encoding="UTF-8"?>
<definitions name="CalculatorService"
targetNamespace="http://www.examples.com/CalculatorService/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.examples.com/CalculatorService/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="http://www.examples.com/CalculatorService/">
<xsd:element name="AddRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="a" type="xsd:int"/>
<xsd:element name="b" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="AddResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="result" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="AddInput">
<part name="parameters" element="tns:AddRequest"/>
</message>
<message name="AddOutput">
<part name="parameters" element="tns:AddResponse"/>
</message>
<portType name="CalculatorPort">
<operation name="Add">
<input message="tns:AddInput"/>
<output message="tns:AddOutput"/>
</operation>
</portType>
<binding name="CalculatorBinding" type="tns:CalculatorPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="Add">
<soap:operation soapAction="Add"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="CalculatorService">
<port name="CalculatorPort" binding="tns:CalculatorBinding">
<soap:address location="http://localhost:${PORT}/soap/calculator"/>
</port>
</service>
</definitions>`;
app.use('/soap/calculator', soap({
services: {
CalculatorService: {
CalculatorPort: {
Add: ({ a, b }, res) => {
console.log(`Received Add request: a=${a}, b=${b}`);
res({
result: a + b
});
}
}
}
},
wsdl: myWsdl
}));
app.get('/', (req, res) => {
res.send(`
<h1>Express SOAP Server Running</h1>
<p>SOAP endpoint at <a href="http://localhost:${PORT}/soap/calculator?wsdl">http://localhost:${PORT}/soap/calculator?wsdl</a></p>
<p>Try sending a SOAP request to calculate sum (e.g., using SoapUI or a client library).</p>
`);
});
app.listen(PORT, () => {
console.log(`Express SOAP server listening on port ${PORT}`);
console.log(`Access WSDL at http://localhost:${PORT}/soap/calculator?wsdl`);
});