Calling a SOAP service, and why REST usually wins
The raw HTTP request a SOAP call produces, how faults are reported, and an honest comparison with REST today.
The call on the wire
curl -sS https://api.example.com/quotes \
-H 'Content-Type: text/xml; charset=utf-8' \
-H 'SOAPAction: "urn:example:quotes/GetQuote"' \
--data-binary @request.xmlimport requests
envelope = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:q="urn:example:quotes">
<soap:Body>
<q:GetQuote><q:symbol>AAPL</q:symbol></q:GetQuote>
</soap:Body>
</soap:Envelope>"""
r = requests.post(
"https://api.example.com/quotes",
data=envelope.encode("utf-8"),
headers={
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": '"urn:example:quotes/GetQuote"',
},
timeout=30,
)
r.raise_for_status()
# a SOAP fault comes back with HTTP 500 and a structured body
if "Fault" in r.text:
raise RuntimeError(r.text)- The XML declaration matters: send UTF-8 and state the encoding in both the XML header and
Content-Type. SOAPActionis required by many SOAP 1.1 servers and is still read by some 1.2 stacks for routing.- Success can arrive with HTTP 200 while the body still contains a fault, so check the body, not only the status code.
- Timeouts and retries need care: a retried request may be processed twice unless the service exposes an idempotency key in the header.
SOAP versus REST
| Dimension | SOAP | REST |
|---|---|---|
| Payload | XML only | JSON in practice, any media type by design |
| Contract | Formal WSDL, machine-readable | OpenAPI usually, often informal |
| Transport | Any, in practice HTTP | HTTP verbs and status codes |
| Security | WS-Security, signed headers | TLS plus OAuth 2 or API keys |
| Tooling | Generated clients, heavyweight | curl, any HTTP client, light SDKs |
| Browser support | Awkward: strict CORS, XML parsing | Native |
| Good fit | Regulated, transactional, long-lived contracts | Public APIs, mobile, most new services |
REST wins for new work because it leans on what HTTP already gives you — methods, status codes, caching, proxies — and because JSON is cheaper to produce, parse and debug. SOAP keeps its ground where an industry body mandates it, where WS-Security or reliable messaging is contractually required, or where a WSDL-driven client is the whole point of the integration.
💡
Most systems end up with both: a SOAP adapter at the edge of the legacy estate, a modern JSON API in front of it. Wrapping rather than rewriting is normally the cheaper and lower-risk path.
FAQ
Do I need a SOAP library?
Not always, but usually yes. A hand-built request is fine for a single known call; for a real integration, generate a client from the WSDL so argument types, namespaces and faults are handled for you.
How do I debug a failed SOAP call?
Log the complete request and response envelopes including headers. Most failures are a namespace mismatch, a missing
SOAPAction, a wrong element order that the XSD requires, or a fault body hidden behind an HTTP 500.Related
WSDL contracts and code generation What SOAP is and how the envelope works
Last refreshed 2026-09-18.