backend / protocols / soap / 02_envelope_and_wsdl.md

SOAP Envelope and WSDL

6 interview angles 6 min read source

SOAP Envelope and WSDL

The two artifacts you’ll actually touch: the message envelope (sent over the wire) and the WSDL (describes the service contract). WSDL drives client code generation, just like OpenAPI for REST or .proto for gRPC.

The SOAP envelope

Every SOAP message has this shape:

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <!-- optional: metadata, auth, addressing, transactions -->
  </soap:Header>
  <soap:Body>
    <!-- required: the actual operation request/response -->
  </soap:Body>
</soap:Envelope>
  • Envelope: the outermost element. Namespace identifies SOAP version (1.1 vs 1.2).
  • Header: optional. Holds extensions (WS-Security tokens, WS-Addressing routing info, custom auth tokens).
  • Body: required. Holds the operation call or response, or a <Fault>.

SOAP 1.1 vs 1.2 differ in:

  • Envelope namespace URI.
  • Content-Type (text/xml for 1.1, application/soap+xml for 1.2).
  • Fault structure.

Most enterprise SOAP services use 1.1; some newer ones use 1.2.

A complete example

Request:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:usr="https://example.com/user/v1">
  <soap:Header>
    <usr:AuthToken>eyJhbGc...</usr:AuthToken>
  </soap:Header>
  <soap:Body>
    <usr:GetUserRequest>
      <usr:Id>42</usr:Id>
      <usr:IncludePosts>true</usr:IncludePosts>
    </usr:GetUserRequest>
  </soap:Body>
</soap:Envelope>

Response:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:usr="https://example.com/user/v1">
  <soap:Body>
    <usr:GetUserResponse>
      <usr:User>
        <usr:Id>42</usr:Id>
        <usr:Name>Alice Smith</usr:Name>
        <usr:Email>alice@example.com</usr:Email>
        <usr:Posts>
          <usr:Post>
            <usr:Id>1001</usr:Id>
            <usr:Title>Hello world</usr:Title>
          </usr:Post>
        </usr:Posts>
      </usr:User>
    </usr:GetUserResponse>
  </soap:Body>
</soap:Envelope>

The element names (GetUserRequest, GetUserResponse, User) are defined in the WSDL/XSD.

Faults — the error model

SOAP errors return HTTP 500 with a <soap:Fault> in the body:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Client</faultcode>
      <faultstring>User not found</faultstring>
      <faultactor>https://example.com/user/v1</faultactor>
      <detail>
        <usr:UserNotFoundError xmlns:usr="https://example.com/user/v1">
          <usr:Id>42</usr:Id>
          <usr:Message>No user with id 42</usr:Message>
        </usr:UserNotFoundError>
      </detail>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>
Element Means
faultcode category — soap:Client (client error), soap:Server (server error), soap:VersionMismatch, soap:MustUnderstand
faultstring human-readable message
faultactor URI of the node that caused the fault
detail application-specific structured error info

SOAP 1.2 changes the names: Code, Reason, Node, Role, Detail. Same idea, different element names.

WSDL — the contract

Web Services Description Language. XML document describing the service.

<wsdl:definitions targetNamespace="https://example.com/user/v1"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:tns="https://example.com/user/v1">

  <!-- 1. Types — data structures, defined in XSD -->
  <wsdl:types>
    <xsd:schema targetNamespace="https://example.com/user/v1">
      <xsd:element name="GetUserRequest">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="Id" type="xsd:int"/>
            <xsd:element name="IncludePosts" type="xsd:boolean" minOccurs="0"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="GetUserResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="User" type="tns:User"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:complexType name="User">
        <xsd:sequence>
          <xsd:element name="Id" type="xsd:int"/>
          <xsd:element name="Name" type="xsd:string"/>
          <xsd:element name="Email" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>

  <!-- 2. Messages — request/response envelopes -->
  <wsdl:message name="GetUserSoapRequest">
    <wsdl:part name="parameters" element="tns:GetUserRequest"/>
  </wsdl:message>
  <wsdl:message name="GetUserSoapResponse">
    <wsdl:part name="parameters" element="tns:GetUserResponse"/>
  </wsdl:message>

  <!-- 3. portType — operations -->
  <wsdl:portType name="UserService">
    <wsdl:operation name="GetUser">
      <wsdl:input message="tns:GetUserSoapRequest"/>
      <wsdl:output message="tns:GetUserSoapResponse"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- 4. Binding — which transport, encoding -->
  <wsdl:binding name="UserServiceSoap" type="tns:UserService">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="GetUser">
      <soap:operation soapAction="https://example.com/UserService/GetUser"/>
      <wsdl:input><soap:body use="literal"/></wsdl:input>
      <wsdl:output><soap:body use="literal"/></wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <!-- 5. Service — endpoint URLs -->
  <wsdl:service name="UserService">
    <wsdl:port name="UserServiceSoap" binding="tns:UserServiceSoap">
      <soap:address location="https://api.example.com/UserService"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

The five sections, top to bottom:

  1. Types: data shapes, defined in XSD (XML Schema).
  2. Messages: named request/response envelopes (each containing parts of those types).
  3. portType: operations available on the service.
  4. Binding: which transport (HTTP), which encoding style.
  5. Service: actual endpoint URLs.

Pattern: a service has ports; ports use bindings; bindings implement portTypes; portTypes group operations; operations reference messages; messages reference types.

XSD — data type definitions

The types section uses XSD (XML Schema Definition):

<xsd:complexType name="User">
  <xsd:sequence>
    <xsd:element name="Id" type="xsd:int"/>
    <xsd:element name="Name" type="xsd:string"/>
    <xsd:element name="Email" type="xsd:string"/>
    <xsd:element name="Phone" type="xsd:string" minOccurs="0"/>     <!-- optional -->
    <xsd:element name="Tags" type="xsd:string" maxOccurs="unbounded"/>  <!-- repeated -->
    <xsd:element name="Status" type="tns:UserStatus"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:simpleType name="UserStatus">
  <xsd:restriction base="xsd:string">
    <xsd:enumeration value="ACTIVE"/>
    <xsd:enumeration value="INACTIVE"/>
    <xsd:enumeration value="DELETED"/>
  </xsd:restriction>
</xsd:simpleType>

XSD is the type system of XML. Built-in types: xsd:int, xsd:string, xsd:boolean, xsd:dateTime, xsd:decimal, xsd:base64Binary, xsd:anyURI, etc.

Validators check incoming XML against the XSD. Code generators turn XSD into Python classes / Java POJOs / etc.

Document vs RPC style; literal vs encoded

SOAP supports four combinations of style + use. Almost all modern services use document/literal (sometimes “wrapped”). The others are historical:

Style Use What it means
document/literal parameter elements directly in body the modern standard
document/literal wrapped one wrapper element per operation also common, simpler codegen
rpc/literal RPC-style with one wrapper rare
rpc/encoded encoded data (with type info) deprecated; avoid

For interview purposes: it’s “document/literal.” If asked to differentiate, “document = data is structured XML matching XSD; literal = no SOAP encoding rules applied to the data.”

Reading a WSDL

Given a WSDL URL, you can typically:

  1. Append ?wsdl to many SOAP endpoints to get the WSDL: https://api.example.com/UserService?wsdl.
  2. Read the <service> section for endpoint URL.
  3. Look in <portType> for available operations.
  4. Look in <types>/<schema> for the data shapes.

Tools like SoapUI parse WSDLs visually; in Python, Zeep does it under the hood (04_python_libraries.md).

WSDL evolution

Like all schema languages, additive changes are typically safe:

  • Adding new operations.
  • Adding optional fields (minOccurs="0").
  • Adding new enum values (often).
  • Adding new types.

Breaking:

  • Removing operations or fields.
  • Making optional fields required.
  • Changing types.
  • Removing enum values.

For breaking changes: publish a new WSDL at a new URL/namespace, run alongside the old.

MTOM/XOP — binary in SOAP

Pure SOAP encodes binary as base64 in XML — bloated and slow. MTOM (Message Transmission Optimization Mechanism) + XOP (XML-binary Optimized Packaging) attach binary as MIME parts:

Content-Type: multipart/related; type="application/xop+xml"; ...

--MIME_boundary
Content-Type: application/xop+xml

<soap:Envelope>...
  <xop:Include href="cid:image1"/>
</soap:Envelope>
--MIME_boundary
Content-Type: image/jpeg

(binary data)
--MIME_boundary--

Used for files in SOAP services. Adds complexity; most libraries handle it transparently.

Common pitfalls

  • Forgetting namespace declarations — XML namespace bugs are subtle and verbose. Validate with the XSD.
  • Confusing SOAP 1.1 and 1.2 — different envelope namespaces, different Content-Type, different fault element names. Check what the server expects.
  • SOAPAction header missing — some servers reject without it.
  • XXE (XML External Entity) attacks — XML parsers fetching external entities; an attacker can read local files or trigger SSRF. Always disable external entity resolution.
  • Signing the wrong element — SAML/WS-Security signatures, XSW attacks. See 03_ws_security.md.
  • Long-lived TCP connections without keepalive — many SOAP libraries don’t pool well by default.

Common interview confusions

  • “WSDL is the same as OpenAPI.” — same role (service contract for codegen) but different format (XML vs YAML) and stricter (XSD types vs OpenAPI’s looser schemas).
  • “SOAP envelopes must have a Header.” — Body is required, Header is optional.
  • SOAPAction is the URL of the endpoint.” — it identifies the operation, not the URL. The endpoint URL is in the <service> section of the WSDL.

Interview angle

  • “What’s the structure of a SOAP message?” — XML envelope with optional Header and required Body. Header carries metadata (security tokens, addressing); Body contains the operation call/response or a <Fault>.
  • “What does a WSDL describe?” — types (data shapes in XSD), messages (request/response), portTypes (operations), bindings (transport + encoding), and services (endpoint URLs). Five sections.
  • “What’s XSD?” — XML Schema Definition, the type system for XML used in WSDL. Defines built-in types (xsd:int, xsd:string, xsd:dateTime) and lets you define complex types.
  • “What’s a soap:Fault?” — SOAP’s error response: faultcode, faultstring, optional faultactor and detail. HTTP status is typically 500. Equivalent of REST’s 4xx/5xx + error body.
  • “SOAP 1.1 vs 1.2?” — different envelope namespaces; 1.1 uses text/xml, 1.2 uses application/soap+xml; fault element names differ. Most enterprise services use 1.1.
  • “What style/use combo do modern SOAP services use?” — document/literal (or document/literal wrapped). The older rpc/encoded style is deprecated.