SOAP anti-pattern
SOAP and WSDL schema coupling
Service contracts fixed in WSDL and XSD, with generated stubs on both sides, where nillable, minOccurs, xsd:choice and SOAP faults carry meaning that a quick JSON port flattens.
- FAMILY
- SOAP
- CUTOVER RISK
- Medium
- Adds migration effort and contract risk, but behavior is visible in the code once you look.
- MODERN MAPPING
- OpenAPI 3.1 with JSON Schema 2020-12 and problem details
- GENERATED ARTIFACT
- openapi.paths.yaml
Before and after
legacy source → modern mapping
Legacy: exhibits the pattern
1<xsd:complexType name="UpdateContactRequest">2 <xsd:sequence>3 <xsd:element name="customerId" type="xsd:string"/>4 <xsd:element name="email" type="xsd:string"5 minOccurs="0" nillable="true"/>6 <xsd:choice>7 <xsd:element name="mobile" type="tns:Phone"/>8 <xsd:element name="landline" type="tns:Phone"/>9 </xsd:choice>10 </xsd:sequence>11</xsd:complexType>1213<wsdl:operation name="UpdateContact">14 <wsdl:input message="tns:UpdateContactRequest"/>15 <wsdl:output message="tns:UpdateContactResponse"/>16 <wsdl:fault name="CustomerNotFound"17 message="tns:CustomerNotFoundFault"/>18</wsdl:operation>
Modern: OpenAPI 3.1 with JSON Schema 2020-12 and problem details
1UpdateContactRequest:2 type: object3 required: [customerId]4 properties:5 customerId: { type: string }6 email:7 type: [string, 'null']8 description: >9 Absent: leave unchanged. null: clear the10 address (xsi:nil in the legacy contract).11 oneOf:12 - required: [mobile]13 properties: { mobile: { $ref: '#/components/schemas/Phone' } }14 - required: [landline]15 properties: { landline: { $ref: '#/components/schemas/Phone' } }
Why it is dangerous in modernization
SOAP services built with JAX-RPC, Axis or JAX-WS are defined by WSDL documents and XSD types, and clients are compiled from them. That makes the XSD the real contract, including details nobody thinks of as business logic: an element with minOccurs="0" may be absent, an element with nillable="true" may be present but explicitly empty, and the service may treat the two differently (absent means 'do not change', nil means 'clear the value'). xsd:choice expresses mutually exclusive alternatives. Business errors travel as typed SOAP faults declared in the WSDL. Older services use RPC/encoded style, which most modern tooling no longer supports. Teams that convert by sampling a few XML messages and writing JSON by hand lose the optionality rules, merge the alternatives into one object, and turn typed faults into a generic 500.
How PYD ENTERPRISES detects it
PYD ENTERPRISES parses WSDL 1.1 (messages, portTypes, bindings, style and use) and the XSDs it imports, and links each operation to the Java or .NET implementation through the generated service endpoint interface or annotations. Within the implementation, dataflow analysis checks how each optional element is read: whether code distinguishes null from absent (for example JAXBElement with isNil, or the specified flags generated by .NET), and which faults are thrown on which paths. The result is a contract model where each element carries its observed semantics, not only its declared type.
Maps to: OpenAPI 3.1 with JSON Schema 2020-12 and problem details
OpenAPI 3.1 aligns with JSON Schema 2020-12, so XSD constructs map cleanly: minOccurs="0" removes the property from required, nillable becomes a type array including null, xsd:choice becomes oneOf, and enumerations become enum. Each declared SOAP fault becomes an error response using the RFC 9457 problem details format with a stable type URI. Where absent and nil mean different things, the generated spec documents both cases explicitly.
Generated specification fragment
1/customers/{customerId}/contact:2 patch:3 operationId: updateContact4 responses:5 '200':6 description: Contact updated7 '404':8 description: SOAP fault CustomerNotFound9 content:10 application/problem+json:11 schema:12 $ref: '#/components/schemas/Problem'13 example:14 type: /errors/customer-not-found15 title: Customer not found16 status: 404
Every generated element links back to the source file and line range shown in the legacy pane. Review and sign off before building against it.
Absent versus nil is a business rule
In the example, the implementation checks whether the email element was sent at all, and if it was, whether it carried xsi:nil="true". Absent leaves the stored email alone; nil deletes it. A JSON port that maps both to null either makes it impossible to clear an email or clears emails on every partial update. The engine finds this by tracing the generated binding object (a JAXBElement in Java, a property plus a specified flag in .NET) to the persistence call, and it writes the distinction into the property description and into two equivalence fixtures.
RPC/encoded services
Services using RPC style with SOAP encoding predate the WS-I Basic Profile, which requires literal use. They use multi-reference values and arrays declared with soapenc:Array, and modern stacks such as JAX-WS do not support them. PYD ENTERPRISES parses them anyway, because they are common in insurance and government integrations from the early 2000s, and maps soapenc arrays to JSON arrays with their item types resolved from the arrayType attribute.
Keeping consumers working during the move
Most programs run SOAP and REST side by side for a while. Because the OpenAPI document is generated from the same contract model as the WSDL analysis, a facade can translate between them field by field, and the generated Postman collection exercises both with identical fixtures. Consumers move when ready, and the equivalence suite shows that both interfaces still return the same business result for the same input.
Related patterns
Usually found in the same codebase.
- .NETMedium
WCF DataContract versioning
Maps to Versioned OpenAPI 3.1 schemas with discriminated oneOf
- Java EEMedium
EJB home and remote interfaces
Maps to Coarse-grained REST contract with DTOs
- CICSCritical
CICS pseudo-conversational state
Maps to Stateless REST resource with explicit versioning
- SpringHigh
Spring XML and AOP hidden logic
Maps to Explicit composition with declared cross-cutting concerns
- Next in catalog
VB6 On Error Resume Next
Find every SOAP and WSDL schema coupling in your codebase.
Run PYD ENTERPRISES in your private VPC and get each occurrence with file, line range, modern mapping and equivalence fixtures, ready for your architects to review.