SOAP APIs Aren't Scary: What You Should Know Before You Build a SOAP Integration
Building your first integration with a SOAP-based API can be daunting.
Recently, I’ve helped several companies integrate their apps with third-party apps and services that use SOAP-based APIs. For developers with SOAP experience, the integrations were a breeze. But for the uninitiated, SOAP has a pretty steep learning curve and throws a lot of new terms and acronyms your way: XML, WSDL, envelope, procedure... and a few dozen others.
Today I want to look at some basic concepts of SOAP, then dive into some tools and resources that make SOAP integrations a lot easier to build (after all, the “S” in SOAP stands for “simple”)!
What Is SOAP?
First, let’s talk about some SOAP basics. If you feel like reading through the entire SOAP spec and its history, you can over at w3.org. I’ll try to give the tl;dr here.
Originally, SOAP stood for “Simple Object Access Protocol.” It was largely built to handle CRUD (create, read, update, delete) operations and it was a protocol to access your objects (like inventory or customer data) in a simple way. A SOAP API would advertise the types of objects that outside services could fetch and manipulate and would outline exactly how a third party should make CRUD requests.
SOAP has since dropped that acronym because it does a lot more than object manipulation, but the idea is still the same: it’s a protocol for two systems to communicate with one another in a predictable way.
Web Services and WSDLs
A SOAP API provides a web service. These web services are made up of one or more procedures (called operations). For example, you might create a “weather forecast” web service, and it could include a “get the 10-day forecast” operation, or an “I’m a weather station, and here’s our latest temperature data” operation.
Requests to each operation take very specific formats for their input, and they have predictable formats for their responses. The “get the 10-day forecast” operation might take a numerical zip code as its input and return an array of floating point temperatures in Fahrenheit that are forecast over the coming ten days for that zip code.
When SOAP-based web services are published, a summary WSDL (Web Services Description Language) file is published. The WSDL, written out in XML, outlines the various operations that the service offers, as well as what inputs and responses you can expect for each operation.
Let’s look at a simple WSDL for a rudimentary “calculator service.” The WSDL (here) defines some basic calculator operations (like addition, subtraction, multiplication, and division). This portion of the calculator WSDL declares that the service has an addition “Add” operation:
<wsdl:operation name="Add">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
Adds two integers. This is a test WebService. ©DNE Online
</wsdl:documentation>
<wsdl:input message="tns:AddSoapIn"/>
<wsdl:output message="tns:AddSoapOut"/>
</wsdl:operation>
If we look further into this XML, we see that the wsdl:input
references a message type tns:AddSoapIn
. Looking a few lines prior where some parameters are declared, we see this section:
<wsdl:message name="AddSoapIn">
<wsdl:part name="parameters" element="tns:Add"/>
</wsdl:message>
That portion of the WSDL references an element tns:Add
, which is found in another previous section of the WSDL. The tns:Add
element defines a complex input type with a couple of integers:
<s:element name="Add">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="intA" type="s:int"/>
<s:element minOccurs="1" maxOccurs="1" name="intB" type="s:int"/>
</s:sequence>
</s:complexType>
</s:element>
Now, one criticism of SOAP is that it is incredibly verbose — this WSDL is no exception, but in layman’s terms all that the above XML really says is “this service has an Add
operation and it takes two integers, intA
and intB
, as inputs.”
Consuming a SOAP API
Okay.... there’s an addition procedure out there that we want to invoke and it takes two integers. Great. How do we go about calling it? SOAP APIs are almost always HTTP-based, so we need to craft an HTTP request from the WSDL we looked at.
SOAP APIs always communicate with XML, so we’ll start by adding a header that sets our Content-Type
to text/xml; charset=utf-8
.
The data we send needs to be in XML format, and SOAP wraps data sent back and forth in a SOAP envelope (an envelope defines the message’s structure). If we look at the calculator WSDL again, we can glean the envelope’s structure. Within our SOAP envelope’s “body,” we’ll declare what procedure we’re going to run (Add
), and we’ll include values for the inputs that the procedure expects (for intA
and intB
). Our HTTP request will end up looking like this:
curl http://www.dneonline.com/calculator.asmx \
--request POST \
--header "Content-Type: text/xml; charset=utf-8" \
--data \
'<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<Add xmlns="http://tempuri.org/">
<intA>15</intA>
<intB>27</intB>
</Add>
</soap:Body>
</soap:Envelope>'
After running that HTTP requests from our command line, we get a response that’s also in XML, and also wrapped in an envelope. The response’s body includes the AddResponse
that’s defined in the WSDL, and that has an AddResult
— the sum of the two numbers we sent to the server:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<AddResponse xmlns="http://tempuri.org/">
<AddResult>42</AddResult>
</AddResponse>
</soap:Body>
</soap:Envelope>
Phew... that’s a hell of a lot of parsing through a WSDL and monkeying with XML schema just to add two numbers together. It’s nice to have predictable request and response formats, but a missing xmlns
XML attribute or typo’d operation name can result in the SOAP server rejecting your requests. Hand-writing these XML requests is pretty error-prone. Let’s reach for some tools to simplify things.
SOAP Tooling
Obviously, manually parsing a WSDL with your eyes and hand-writing HTTP requests is burdensome and should be avoided at all costs. I recommend reaching for a SOAP tool that parses the WSDL for you and presents you with a list of operations (and their inputs) that you can invoke. There are several great apps out there built for exactly that purpose:
- SoapUI from SmartBear is a popular tool that gives you a great graphical UI for navigating through a WSDL. Popping open any operation gives you a sample request that you can fill in and execute from within their app:
- Recent versions of the popular HTTP client Postman also support importing a WSDL, and it even provides you with pre-populated sample requests that you can send to the web service from within the app.
These graphical tools are great for exploring a SOAP API, and I recommend you familiarize yourself with the web service’s operations prior to sitting down and coding up your integration. Once you get a good idea of how the SOAP API works, it’s time to turn to code.
Writing Code to Interact With SOAP APIs
Manually parsing a WSDL and hand-writing HTTP requests is error-prone and just generally an awful experience. You definitely don’t want to resort to templating out XML with string literals. Let’s avoid that when writing code to interact with a SOAP-based web service.
Whether you’re using Python, NodeJS, C#, or any other modern programming language, the chances are good that there’s a SOAP library you can leverage to make it simple to invoke web service operations. In NodeJS, for example, you can reach for the aptly named soap package on NPM.
This library can take the URL of a WSDL as an argument, and in doing so creates a fully functional HTTP client object that can invoke any of the web service’s operations. We can perform something like client.Add
to invoke the “Add” operation, pass in a couple of input arguments, and the rest (parsing the WSDL, formatting the XML request in an envelope, deserializing the XML response, etc.) is handled for you. With just a half-dozen lines of code (I don’t count parentheses!), we can make a request to the calculator API:
var soap = require("soap");
const wsdlUrl = "http://www.dneonline.com/calculator.asmx?WSDL";
const args = { intA: 15, intB: 27 };
soap.createClient(wsdlUrl, function (err, client) {
client.Add(args, (err, result) => {
console.log(`The API returned a sum of ${result.AddResult}`);
});
});
The response to our request contains an AddResult
property, and our function prints out The API returned a sum of 42
, like we’d expect.
Abstracting SOAP Further
If you’re building integrations that connect your own product to other apps your customers use, an embedded integration platform as a service (embedded iPaaS) can abstract much of the complexity of interacting with SOAP APIs. Embedded integration platforms include low-code integration builders with pre-built connectors for popular SOAP-based apps (like Salesforce), which completely eliminates the need to write code to interact with many SOAP-based APIs.
For less common SOAP-based APIs that don’t have built-in connectors, they typically offer a SOAP component that abstracts out the complexity of making SOAP requests.
In many situations, you can leverage an embedded iPaaS to interact with a SOAP-based API while writing little to no code.
Conclusion
Obviously, the calculator web service is incredibly simple, but I think it does a good job illustrating how a SOAP web service can appear daunting at first, but with the right tooling, it’s relatively clean and simple to build an integration with a SOAP-based API.