XML Web Services — SOAP & REST with XML
In this tutorial, you'll learn about XML Web Services. We cover key concepts, practical examples, and best practices.
XML web services use structured XML messages for systems communication — with SOAP providing a formal protocol and REST offering resource-based APIs.
What You'll Learn
- The SOAP protocol envelope, header, body, and fault structures
- How WSDL defines service contracts, operations, and message types
- Building REST APIs that consume and produce XML payloads
- Security considerations including XML signing, encryption, and WS-Security
Why It Matters
Enterprise systems — banking, healthcare (HL7), government, insurance — rely on XML web services for transactional reliability, schema enforcement, and cross-platform interoperability. Every major security tool, including Durga Antivirus Pro, uses XML-based APIs for threat intelligence feeds and centralized management consoles.
Learning Path
flowchart LR A[XML Basics] --> B[XML vs JSON vs YAML] B --> C[RSS & Atom Feeds] C --> D[XML Configuration Files] D --> E[XML Web Services
You are here]
SOAP — Simple Object Access Protocol
SOAP is a messaging protocol that defines a strict XML structure for exchanging structured data. Think of SOAP as a standardized envelope: every message has the same format regardless of what's inside, making it predictable and reliable.
SOAP Message Structure
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header>
<auth:Authentication xmlns:auth="http://durga-antivirus.com/auth">
<auth:ApiKey>abc123-def456-ghi789</auth:ApiKey>
<auth:Timestamp>2026-06-20T10:30:00Z</auth:Timestamp>
<auth:Signature>base64signature==</auth:Signature>
</auth:Authentication>
</soap:Header>
<soap:Body>
<tns:ScanFile xmlns:tns="http://durga-antivirus.com/scan">
<tns:FileName>suspicious.doc</tns:FileName>
<tns:FileContent>base64encodedcontent==</tns:FileContent>
<tns:ScanOptions>
<tns:HeuristicLevel>high</tns:HeuristicLevel>
<tns:CheckArchives>true</tns:CheckArchives>
</tns:ScanOptions>
</tns:ScanFile>
</soap:Body>
</soap:Envelope>
SOAP Envelope Components
| Component | Required | Description |
|---|---|---|
<Envelope> |
Yes | Root element that wraps the entire message |
<Header> |
No | Metadata: authentication, routing, transaction context |
<Body> |
Yes | The actual request or response data |
<Fault> |
Conditional | Error information (appears in place of Body on failure) |
SOAP Fault Response
When a SOAP service encounters an error, it returns a <Fault> element inside the Body:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>File scan failed</faultstring>
<faultactor>https://scan.durga-antivirus.com/soap</faultactor>
<detail>
<tns:ScanFault xmlns:tns="http://durga-antivirus.com/scan">
<tns:ErrorCode>SCAN-1004</tns:ErrorCode>
<tns:ErrorMessage>File exceeds maximum scan size of 100MB</tns:ErrorMessage>
<tns:FileSize unit="MB">150</tns:FileSize>
</tns:ScanFault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
| Fault Element | Description |
|---|---|
<faultcode> |
Machine-readable error type (soap:VersionMismatch, soap:MustUnderstand, soap:Client, soap:Server) |
<faultstring> |
Human-readable error description |
<faultactor> |
URI identifying the source of the fault |
<detail> |
Application-specific error details |
WSDL — Web Services Description Language
WSDL is an XML document that describes a web service's interface — what operations it offers, what messages it expects, and how to communicate with it. Think of WSDL as a restaurant menu: it tells you what dishes are available, what ingredients they contain, and how to order them.
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="ScanService"
targetNamespace="http://durga-antivirus.com/scan"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://durga-antivirus.com/scan"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Data types used in messages -->
<types>
<xsd:schema targetNamespace="http://durga-antivirus.com/scan">
<xsd:element name="ScanFileRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="FileName" type="xsd:string"/>
<xsd:element name="FileContent" type="xsd:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ScanFileResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ThreatFound" type="xsd:boolean"/>
<xsd:element name="ThreatName" type="xsd:string" minOccurs="0"/>
<xsd:element name="Severity" type="xsd:string" minOccurs="0"/>
<xsd:element name="ScanDuration" type="xsd:double"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<!-- Abstract messages -->
<message name="ScanFileRequestMessage">
<part name="parameters" element="tns:ScanFileRequest"/>
</message>
<message name="ScanFileResponseMessage">
<part name="parameters" element="tns:ScanFileResponse"/>
</message>
<!-- Port type (abstract interface) -->
<portType name="ScanPortType">
<operation name="ScanFile">
<input message="tns:ScanFileRequestMessage"/>
<output message="tns:ScanFileResponseMessage"/>
<fault name="ScanFault" message="tns:ScanFaultMessage"/>
</operation>
</portType>
<!-- Binding (protocol + data format) -->
<binding name="ScanBinding" type="tns:ScanPortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="ScanFile">
<soap:operation soapAction="http://durga-antivirus.com/scan/ScanFile"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault>
<soap:fault name="ScanFault" use="literal"/>
</fault>
</operation>
</binding>
<!-- Service endpoint -->
<service name="ScanService">
<port name="ScanPort" binding="tns:ScanBinding">
<soap:address location="https://scan.durga-antivirus.com/soap/scan"/>
</port>
</service>
</definitions>
WSDL Structure Layers
| Section | Purpose |
|---|---|
<types> |
Defines data types (usually XSD) used in messages |
<message> |
Abstract definition of input/output/fault messages |
<portType> |
Abstract interface — groups operations |
<binding> |
Concrete protocol and data format binding |
<service> |
Physical endpoint URL where the service lives |
REST with XML
While REST APIs commonly use JSON, many enterprise APIs still use XML. REST with XML uses HTTP methods (GET, POST, PUT, DELETE) with XML request and response bodies.
import requests
import xml.etree.ElementTree as ET
# REST API endpoint that accepts XML
url = "https://api.durga-antivirus.com/v1/threats"
# Build XML request body
threat_report = ET.Element("ThreatReport")
threat_report.set("xmlns", "http://durga-antivirus.com/threats")
header = ET.SubElement(threat_report, "Header")
ET.SubElement(header, "Source").text = "endpoint-01"
ET.SubElement(header, "Timestamp").text = "2026-06-20T10:30:00Z"
ET.SubElement(header, "ApiKey").text = "abc123-def456"
threats = ET.SubElement(threat_report, "Threats")
threat1 = ET.SubElement(threats, "Threat",
type="malware", severity="critical")
ET.SubElement(threat1, "Name").text = "Trojan.Generic.12345"
ET.SubElement(threat1, "FilePath").text = "C:\\Users\\user\\invoice.exe"
ET.SubElement(threat1, "MD5").text = "d41d8cd98f00b204e9800998ecf8427e"
ET.SubElement(threat1, "Action").text = "quarantined"
xml_body = ET.tostring(threat_report, encoding="unicode")
# POST XML to the API
headers = {"Content-Type": "application/xml"}
response = requests.post(url, data=xml_body, headers=headers)
# Parse XML response
response_root = ET.fromstring(response.text)
status = response_root.find(".//{http://durga-antivirus.com/threats}Status")
print(f"Response status: {status.text}")
Expected output:
Response status: ACCEPTED
Building an XML REST Endpoint with Flask
from flask import Flask, request, Response
import xml.etree.ElementTree as ET
app = Flask(__name__)
@app.route("/api/v1/scan", methods=["POST"])
def scan_file():
content_type = request.headers.get("Content-Type", "")
if "application/xml" not in content_type:
return Response(
"<error>Content-Type must be application/xml</error>",
status=415,
mimetype="application/xml"
)
try:
root = ET.fromstring(request.data)
ns = {"tns": "http://durga-antivirus.com/scan"}
file_name = root.find("tns:FileName", ns).text
options = root.find("tns:ScanOptions", ns)
# Simulate scan
heuristic = options.find("tns:HeuristicLevel", ns).text
# Build XML response
response = ET.Element("ScanResponse")
ET.SubElement(response, "ThreatFound").text = "false"
ET.SubElement(response, "ThreatName")
ET.SubElement(response, "Severity").text = "none"
ET.SubElement(response, "ScanDuration").text = "1.234"
xml_response = ET.tostring(response, encoding="unicode")
return Response(xml_response, mimetype="application/xml")
except ET.ParseError as e:
return Response(
f"<error>Invalid XML: {str(e)}</error>",
status=400,
mimetype="application/xml"
)
if __name__ == "__main__":
app.run(port=5000, debug=True)
Test the endpoint:
curl -X POST http://localhost:5000/api/v1/scan \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?>
<ScanRequest xmlns="http://durga-antivirus.com/scan">
<FileName>test.doc</FileName>
<ScanOptions>
<HeuristicLevel>high</HeuristicLevel>
</ScanOptions>
</ScanRequest>'
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<ScanResponse>
<ThreatFound>false</ThreatFound>
<ThreatName/>
<Severity>none</Severity>
<ScanDuration>1.234</ScanDuration>
</ScanResponse>
SOAP Client Example in Python
import requests
# SOAP 1.1 request template
soap_request = """<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:scan="http://durga-antivirus.com/scan">
<soap:Header>
<scan:ApiKey>abc123-def456</scan:ApiKey>
</soap:Header>
<soap:Body>
<scan:ScanFile>
<scan:FileName>suspicious.doc</scan:FileName>
<scan:FileContent>{base64_content}</scan:FileContent>
</scan:ScanFile>
</soap:Body>
</soap:Envelope>"""
# Send SOAP request
headers = {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": "http://durga-antivirus.com/scan/ScanFile"
}
response = requests.post(
"https://scan.durga-antivirus.com/soap/scan",
data=soap_request,
headers=headers
)
print(response.text)
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<scan:ScanFileResponse xmlns:scan="http://durga-antivirus.com/scan">
<scan:ThreatFound>true</scan:ThreatFound>
<scan:ThreatName>Trojan.Generic.12345</scan:ThreatName>
<scan:Severity>critical</scan:Severity>
<scan:ScanDuration>2.345</scan:ScanDuration>
</scan:ScanFileResponse>
</soap:Body>
</soap:Envelope>
WS-Security
WS-Security (WSS) is an extension that adds security to SOAP messages — signing, encryption, and tokens:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsse:Security>
<wsse:UsernameToken wsu:Id="UsernameToken-1">
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
base64digest=
</wsse:Password>
<wsse:Nonce>base64nonce=</wsse:Nonce>
<wsu:Created>2026-06-20T10:30:00Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body wsu:Id="Body-1">
<tns:GetThreatIntel xmlns:tns="http://durga-antivirus.com/intel">
<tns:ThreatHash>d41d8cd98f00b204e9800998ecf8427e</tns:ThreatHash>
</tns:GetThreatIntel>
</soap:Body>
</soap:Envelope>
SOAP vs REST with XML
| Aspect | SOAP | REST with XML |
|---|---|---|
| Protocol | Formal, rigid | Architectural style |
| Transport | HTTP, SMTP, JMS | HTTP only |
| State | Stateless or stateful | Stateless |
| Caching | Not supported | Built-in (HTTP caching) |
| Security | WS-Security (built-in) | HTTPS + tokens (external) |
| Transaction support | Built-in (WS-AtomicTransaction) | Manual |
| Discovery | WSDL (self-describing) | Documentation or OpenAPI |
| Error handling | SOAP Fault (standardized) | HTTP status codes |
| Performance | Slower (XML parsing overhead) | Faster |
| Tooling | Extensive (code generation) | Minimal (plain HTTP) |
Common Mistakes
1. Missing SOAPAction header
SOAP 1.1 requires the SOAPAction HTTP header. Without it, many servers reject the request.
2. Forgetting namespace prefixes
<!-- WRONG: missing namespace prefix in Body -->
<Body>
<ScanFile>...</ScanFile>
</Body>
<!-- CORRECT -->
<soap:Body>
<scan:ScanFile>...</scan:ScanFile>
</soap:Body>
3. Improper XML escaping in payloads
Binary data like file contents must be base64-encoded inside XML, not included raw.
4. Not validating WSDL before code generation
Invalid WSDL produces broken client stubs. Always validate WSDL with tools like xmllint.
5. Hardcoding endpoint URLs
# WRONG
url = "http://localhost:8080/soap"
# RIGHT
url = os.getenv("SOAP_ENDPOINT", "http://localhost:8080/soap")
6. XML parser vulnerabilities
XXE and XML bomb attacks are especially dangerous in web services because parsers process untrusted data from the network.
7. Content-Type mismatch
Sending XML to an endpoint expecting JSON (or vice versa) returns HTTP 415 Unsupported Media Type.
Practice Questions
What is the purpose of WSDL in SOAP web services? WSDL is a machine-readable contract that describes available operations, input/output messages, data types, and endpoint URLs — enabling automatic client code generation.
What is the difference between SOAP and REST? SOAP is a formal protocol with built-in security, transactions, and reliability — rigid but standardized. REST is an architectural style using plain HTTP — simpler, faster, and more flexible.
What does a SOAP Fault element contain?
<faultcode>(error type),<faultstring>(description),<faultactor>(source), and<detail>(app-specific error data).How do you secure a SOAP web service? Use WS-Security for message-level signing and encryption, HTTPS for transport security, API keys or tokens for authentication, and input validation against XSD schemas.
When would you choose SOAP over REST? When you need built-in transaction support, formal contracts (WSDL), enterprise-grade security (WS-Security), or reliable messaging (WS-ReliableMessaging) — common in finance, healthcare, and government.
Challenge: Build a SOAP-based threat intelligence service that accepts a file hash, queries a signature database, and returns threat metadata (name, severity, category, first seen date) in a structured SOAP response with proper fault handling.
Real-world task: Durga Antivirus Pro needs a centralized management API. Design a RESTful XML API that allows administrators to list, create, update, and delete scan policies. Each policy includes name, scan paths, exclusion patterns, heuristic level, and schedule. Implement the GET and POST endpoints with XML request/response handling.
FAQ
What's Next
| Tutorial | What You'll Learn |
|---|---|
| XML Digital Signatures | Sign and verify XML documents for security |
| XSLT Explained — Transform XML into HTML | Transform XML responses into readable formats |
| XPath Explained — Querying XML | Navigate XML documents to extract specific data |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro