Part 2: WSDL and Service Contracts

Reading a WSDL for the First Time

The first time I opened a WSDL file, I closed it immediately. It was over 2,000 lines of nested XML with namespaces I had never seen. I did what most developers do: searched for a tool to generate code from it and moved on without understanding what was inside.

That approach worked until it didn't. When the generated client behaved unexpectedly — passing values in the wrong order, serialising optional fields incorrectly — I had no idea where to look. I had to go back and actually read the WSDL.

Understanding WSDL is a skill worth building. It is the formal contract between you and the service. When something goes wrong, the WSDL is where the answer is.

What is WSDL?

WSDL (Web Services Description Language) is an XML-based document that describes a SOAP web service. It answers:

  • What operations does the service offer?

  • What input does each operation expect?

  • What output does each operation return?

  • What data types are used?

  • Where is the service hosted (endpoint URL)?

  • What protocol does it use?

WSDL is to SOAP what OpenAPI (Swagger) is to REST — but with stricter enforcement. A well-written WSDL completely and unambiguously describes a service.

WSDL Structure

A WSDL document is made up of six major sections. Each builds on the previous.

Section 1: <types>

This is where data types are defined using XSD (XML Schema Definition). It describes the structure of the XML elements that appear in requests and responses.

Key XSD primitives you will encounter repeatedly:

XSD Type
Python equivalent
Notes

xsd:string

str

xsd:integer

int

xsd:decimal

Decimal

Do not use float for money

xsd:boolean

bool

Values are true / false (lowercase)

xsd:dateTime

datetime

ISO 8601 format

xsd:date

date

xsd:base64Binary

bytes

For file attachments

xsd:anyType

Any

Avoid: undefined structure

Section 2: <message>

Messages define the input and output payloads for operations. Each message refers to elements defined in the <types> section.

The element attribute references an element defined in the <types> XSD. In Document/Literal style (the most common), each message has exactly one part with an element reference.

Section 3: <portType>

The portType is the abstract service interface — it lists operations without specifying how or where they run. Think of it as a Python abstract base class.

Operations can have:

  • input only — one-way operation (fire and forget)

  • input + output — standard request-response

  • input + output + fault — request-response with explicit error type

Section 4: <binding>

The binding maps the abstract portType to a concrete protocol (SOAP) and specifies the communication style and encoding.

Key fields to read:

  • style="document" — Document style (vs rpc)

  • use="literal" — Literal encoding (vs encoded; always prefer literal)

  • soapAction — The SOAPAction HTTP header value (SOAP 1.1 only)

Section 5: <service>

The service element specifies the actual network address where the service is deployed.

This is what zeep uses when you load a WSDL — it reads the location to know where to send requests.

Reading a Real WSDL with zeep

Once you understand the structure, you can use zeep to inspect any WSDL programmatically.

Output:

Inspecting Operation Signatures

Before calling any operation, I always check what the operation expects as input and what it returns.

For complex services, zeep also provides a helper to pretty-print the full type structure:

Writing a Minimal WSDL From Scratch

When building a SOAP service with spyne (covered in Part 3), the WSDL is generated automatically. But understanding how to write one manually helps when working with systems that require a handcrafted contract or when debugging generated WSDLs.

Here is a complete, minimal WSDL for a simple greeting service:

Save this as greeting.wsdl and load it with zeep to verify it is valid:

Common WSDL Patterns in the Wild

After working with several enterprise SOAP integrations, these are the patterns I encounter most frequently.

Fault Messages in portType

Most enterprise services declare explicit fault types. Always check if the portType operations have fault elements — they tell you what error types to handle.

Imported XSD Schemas

Large WSDLs often separate type definitions into external .xsd files and import them:

zeep handles imported schemas automatically. When loading WSDLs behind corporate firewalls, these imports can fail if the schema URLs are internal. In that case, download the schemas manually and update the schemaLocation to a local path.

Multiple Ports

A WSDL service can define multiple ports — often one for SOAP 1.1 and one for SOAP 1.2:

When using zeep, specify which port to use:

What's Next

You now understand:

  • The six sections of a WSDL document

  • How to read types, messages, portType, binding, and service

  • How to inspect a WSDL with zeep

  • How to write a minimal WSDL from scratch

  • Common patterns in enterprise WSDLs

In Part 3, we build a working SOAP service from scratch using spyne — defining operations, modelling complex types, and serving the endpoint over HTTP.

Last updated