WSDL to OpenAPI Converter

WSDL documents describing SOAP based Web Services can be converted into OpenAPI specifications describing APIs with JSON messages. The WSDL and the included XML Schemas (XSD) provide all the data for the transformation.

Membrane API Gateway provides a converter that automatically translates WSDL operations and XML Schema types into OpenAPI operations and JSON Schemas.

WSDL to OpenAPI Converter

The OpenAPI specification can be used to generate client code and server implementations. It also provides the mappings required by Membrane's SOAP to REST gateway to transform between JSON and SOAP/XML.

WSDL operations can also be mapped to HTTP methods and resource paths to expose the existing SOAP Web Service as a RESTful API.

Mapping WSDL Operations to OpenAPI Endpoints

The snippet shows a WSDL portType with five operations:

<wsdl:portType name="PartnerPT">
    <wsdl:operation name="getPartner">
        ...
    </wsdl:operation>
    <wsdl:operation name="getPartners">
        ...
    </wsdl:operation>
    <wsdl:operation name="createPartner">
        ...
    </wsdl:operation>
    <wsdl:operation name="updatePartner">
        ...
    </wsdl:operation>
    <wsdl:operation name="deletePartner">
        ...
    </wsdl:operation>
</wsdl:portType>

The converter automatically translates these WSDL operations into OpenAPI endpoints.

WSDL operations converted to OpenAPI endpoints

By default, the generated API follows the Remote Procedure Call (RPC) style rather than REST principles. The paths represent operations, such as update-partner, instead of resources such as partners, and all endpoints use the POST method. This operation-oriented style is well suited for APIs that represent actions or business processes. If you prefer a resource-oriented RESTful API, the converter also allows you to map WSDL operations to HTTP methods and resource paths.

Mapping WSDL Operations to REST Resources

A WSDL typically describes operations such as:

A resource-oriented REST API provides the same functionality through resources and HTTP methods:

GET|POST /partners
GET|PUT|DELETE /partners/{id}

With Membrane, you can define an HTTP method and URI template for each WSDL operation to expose the SOAP Web Service as resources:

api:
  port: 2000
  name: Partner REST API
  flow:
    - wsdl2openapi:
        wsdl: partner.wsdl
        operations:
          getPartners:
            method: GET
            path: /partners
          getPartner:
            method: GET
            path: /partners/{id}
          createPartner:
            path: /partners
            method: POST
          updatePartner:
            method: PUT
            path: /partners/{id}
          deletePartner:
            method: DELETE
            path: /partners/{id}

The converter uses these mappings to generate an OpenAPI description with resource-oriented REST endpoints:

WSDL operations mapped to RESTful OpenAPI endpoints
Figure: WSDL operations mapped to RESTful OpenAPI endpoints

Membrane does not automatically decide how WSDL operations should be mapped to REST resources, because choosing meaningful resources, paths, and HTTP methods is an API design decision. However, an AI coding assistant can generate an initial mapping for you.

Let an AI Coding Assistant Do the REST Mapping

An AI coding assistant can help you convert a WSDL into a RESTful OpenAPI with Membrane. Follow these steps:

  1. Download and unpack Membrane API Gateway.
  2. Open a terminal and change to the Membrane distribution directory:
    cd membrane-api-gateway-*
  3. Start your AI coding assistant in this directory.
  4. Copy the prompt below and replace <WSDL URL or path> with the location of your WSDL.
  5. Let the coding assistant generate the apis.yaml configuration.
  6. Start Membrane with the generated configuration:
    ./membrane.sh -c apis.yaml
You're in the Membrane API Gateway distribution directory.

First, study the tutorials in tutorials/soap/, especially
95-WSDL-to-OpenAPI.yaml, 96-WSDL-to-OpenAPI-REST.yaml, and
97-WSDL-XSD-Features.yaml.

Then create an apis.yaml that exposes the SOAP service described by
<WSDL URL or path> as a REST API using wsdl2openapi.

Read the WSDL and map each SOAP operation to a RESTful resource:

- Derive resource paths from the business nouns in the operation names
  (GetCustomer -> GET /customers/{id}, CreateOrder -> POST /orders, ...).
- Choose the HTTP method based on the operation's semantics:
  read -> GET, create -> POST, full update -> PUT,
  partial update -> PATCH, remove -> DELETE.
- Use plural resource names and path parameters for identifiers.
- Group related operations under a common tag.
- Keep the mappings consistent.
- If an operation has no natural REST representation, choose a reasonable
  mapping and explain the compromise.

Configure the mappings under the `operations` element of wsdl2openapi,
giving each operation a `method`, `path`, and `tag`.

Configure the SOAP service described by the WSDL as the backend target.

Show me a mapping table with:
SOAP operation -> HTTP method -> REST path

Finally, explain how to start Membrane with the generated configuration
and how to open http://localhost:2000/api-docs to access the generated
OpenAPI documentation.

Mapping SOAP Parameters to REST Path Parameters

Consider a SOAP operation that retrieves a partner by ID:

getPartner(id)

The Web Service expects the id as an XML element in the request:

<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
  <s11:Body>
    <ns:getPartnerRequest xmlns:ns="http://example.com/partner">
      <id>1</id>
    </ns:getPartnerRequest>
  </s11:Body>
</s11:Envelope>

To expose this operation as a RESTful GET endpoint, map the id element to a path parameter:

getPartner:
    method: GET
    path: /partners/{id}

The WSDL operation is now represented in the generated OpenAPI description as a RESTful resource with an id path parameter:

RESTful OpenAPI endpoint from a WSDL

Sidenote: Actually this isn't a resource but a URI template for resources.

GET Requests and Query Parameters

Consider a SOAP get-operation that accepts multiple parameters in the request body:

<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
  <s11:Body>
    <ns:getPartnersRequest xmlns:ns="http://example.com/partner">
      <city>Paris</city>
      <kind>COMPANY</kind>
    </ns:getPartnersRequest>
  </s11:Body>
</s11:Envelope>

The SOAP operation can be mapped to a RESTful GET endpoint:

getPartners:
    method: GET
    path: /partners

Since a GET request has no request body in the generated API, the converter maps the SOAP input elements to OpenAPI query parameters.

SOAP parameters mapped to OpenAPI query parameters for a REST GET endpoint

A REST client can now call the operation using a query string:

GET /partners?city=Paris&kind=COMPANY

Supported XML Schema Features

The converter supports the following XML Schema (XSD) features.

Type Declarations

  • Named xsd:complexType
  • Inline xsd:complexType and xsd:simpleType
  • Named xsd:simpleType restrictions, resolved to their base primitive
  • Recursive / self-referential types
  • Type references by type= attribute and element references by ref=

Content Models

  • xsd:sequence and xsd:all, including arbitrary nesting
  • xsd:choice. All alternatives become properties, plus a oneOf that requires exactly one of them; optional and repeatable choices are documented in the schema description
  • xsd:group references
  • minOccurs="0" → optional property; anything else → required
  • maxOccurs="unbounded" or > 1 → array

Derivation

  • xsd:complexContent / xsd:extension
  • xsd:complexContent / xsd:restriction
  • xsd:simpleContent extension and restriction

Attributes

  • xsd:attribute mapped to an @-prefixed property
  • use="required"

Facets (Constraints, Enforced by Validation)

  • enumeration (typed to the field's own type — numeric, boolean, string)
  • pattern (anchored; multiple patterns combined as alternatives)
  • length, minLength, maxLength
  • minInclusive, maxInclusive, minExclusive, maxExclusive (OpenAPI 3.1 exclusive-bound keywords)

Values and Nullability

  • default=
  • fixed=
  • nillable="true" (3.1 "null" type)

Built-in Types

  • string, boolean, int/long (with int32/int64), float, double, decimal
  • date, dateTime, time, duration, anyURI, base64Binary, hexBinary → proper format
  • normalizedString, token, language, QName, NOTATION, the gYear/gMonth/gDay/gYearMonth/gMonthDay family
  • The full bounded/unbounded integer family (integer, short, byte, positiveInteger, unsignedLong, …)
  • Where type/format cannot name the original XSD type, it is carried in an x-xsd-type extension so tools can recover it

Schema Composition & Documentation

  • xsd:import and xsd:include, resolved across the full import graph (transitively)
  • Cross-namespace type and element references; same-local-name collisions across namespaces get namespace-qualified keys
  • xsd:documentation carried over as the schema description

WSDL Message Styles

  • Document/literal wrapped (single part with element=), document/literal bare (multiple parts), RPC-style parts (type=)
  • Declared faults, mapped to a detail schema with one alternative per fault

Not Supported

The following constructs degrade silently. No exceptions are thrown:

Wildcards

  • xsd:any
  • xsd:anyAttribute

Simple Type Constructions

  • xsd:list A whitespace-separated list type falls through to plain string
  • xsd:union
  • xsd:simpleType without a restriction child resolves to string

Polymorphism

  • Substitution groups: Only the declared element is emitted, never its substitutes
  • abstract="true" types and xsi:type at runtime

Reuse Constructs

  • xsd:attributeGroup Attribute groups are not expanded (only direct xsd:attribute children are read); xsd:group for elements is supported
  • xsd:redefine and xsd:override

Facets Without a JSON Schema Equivalent

  • totalDigits, fractionDigits, whiteSpace are ignored by design
  • XSD regex dialect: pattern values are copied verbatim, so a construct only XSD has (e.g. \p{IsBasicLatin}, character-class subtraction) stays unusable in an ECMA regex engine

Content Model Nuances

  • Mixed content (mixed="true"). The text alongside child elements has no representation.
  • xsd:all is treated identically to xsd:sequence; its "each at most once, any order" rule is not separately enforced
  • Occurrence counts beyond "one vs. many": minOccurs="2" or maxOccurs="5" do not become minItems/maxItems
  • Element/attribute uniqueness and referential constraints — xsd:unique, xsd:key, xsd:keyref
  • XSD 1.1 xsd:assert / xsd:alternative

Other

  • nillable on a declaration whose type is a shared component forces the type inline rather than being expressed on the reference (a design choice, not a gap, but it means such types are duplicated)
  • A choice that is optional (minOccurs="0"), repeatable (maxOccurs>1), or has an all-optional alternative cannot be encoded as oneOf — the constraint is stated in the description and is not enforced by validation

If you need a construct that the converter does not support yet, open an issue at our GitHub repository or send us an email at info@predic8.de.