wsdlopenapiapi-designtutorial

Convert WSDL to OpenAPI When You Cannot Change the SOAP Service

SOAPless Team6 min read

The most practical reason to convert WSDL to OpenAPI is not documentation vanity. It is that downstream teams do not want to read WSDL just to consume a fixed upstream SOAP service.

That happens all the time when:

  • the upstream contract belongs to a vendor
  • a government or partner endpoint is outside your control
  • one integration team does not want every other team to re-learn XML and WSDL details

OpenAPI becomes useful because it gives the rest of the organization a contract they can actually work with.

This guide focuses on that real-world case: the SOAP service stays as-is, but you still need a stable, modern interface for the teams on your side of the boundary.

Why Convert WSDL to OpenAPI?

  • Modern documentation. Swagger UI and Redoc render OpenAPI specs into interactive API docs. There's no equivalent experience for WSDL files.
  • Client generation. Tools like openapi-generator produce clients in 50+ languages from an OpenAPI spec. WSDL-based code generation is limited to a few languages with aging tooling.
  • API gateway compatibility. Kong, AWS API Gateway, and Apigee all import OpenAPI specs natively. WSDL support is limited or nonexistent.
  • Developer onboarding. New developers are far more likely to understand REST/JSON than SOAP/XML.

If your goal is not just documentation but an actual managed integration layer, this usually pairs with:

  • a REST facade in front of SOAP
  • generated or synchronized OpenAPI
  • one test surface for downstream teams
  • one place to normalize upstream SOAP faults

The Conceptual Mapping

Before converting, understand how SOAP concepts map to REST:

WSDL ConceptOpenAPI Equivalent
<wsdl:service>Server object
<wsdl:portType> / <wsdl:operation>Path + HTTP method
<wsdl:message> + <wsdl:part>Request/response body schema
<xs:complexType>JSON Schema object in components/schemas
<xs:simpleType>JSON Schema primitive with constraints
<soap:address location="...">servers[0].url
SOAPAction headerNot needed (path-based routing)
SOAP faultError response schema (4xx/5xx)

Approach 1: Manual Conversion

For services with a small number of operations, manual conversion gives you the most control and produces the cleanest output.

Step 1: Extract Operations

Open the WSDL and identify all operations in the <wsdl:portType>:

<wsdl:portType name="UserServicePort">
  <wsdl:operation name="GetUser">
    <wsdl:input message="tns:GetUserRequest"/>
    <wsdl:output message="tns:GetUserResponse"/>
    <wsdl:fault name="UserNotFound" message="tns:UserNotFoundFault"/>
  </wsdl:operation>
  <wsdl:operation name="CreateUser">
    <wsdl:input message="tns:CreateUserRequest"/>
    <wsdl:output message="tns:CreateUserResponse"/>
  </wsdl:operation>
</wsdl:portType>

Step 2: Map Operations to Paths

Each SOAP operation becomes an OpenAPI path. Choose RESTful paths and HTTP methods:

openapi: "3.0.3"
info:
  title: User Service
  version: "1.0.0"
servers:
  - url: https://api.example.com/services

paths:
  /users/{userId}:
    get:
      operationId: getUser
      summary: Retrieve a user by ID
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: User found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "404":
          description: User not found

  /users:
    post:
      operationId: createUser
      summary: Create a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateUserRequest"
      responses:
        "201":
          description: User created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"

Step 3: Convert XSD Types to JSON Schema

This is where most of the work lives. Map each xs:complexType from the WSDL's <wsdl:types> section to a JSON Schema definition:

<!-- XSD -->
<xs:complexType name="User">
  <xs:sequence>
    <xs:element name="id" type="xs:int"/>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="email" type="xs:string" minOccurs="0"/>
    <xs:element name="role" type="tns:RoleEnum"/>
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="RoleEnum">
  <xs:restriction base="xs:string">
    <xs:enumeration value="admin"/>
    <xs:enumeration value="user"/>
    <xs:enumeration value="viewer"/>
  </xs:restriction>
</xs:simpleType>
# JSON Schema (OpenAPI)
components:
  schemas:
    User:
      type: object
      required: [id, name]
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
        role:
          $ref: "#/components/schemas/RoleEnum"

    RoleEnum:
      type: string
      enum: [admin, user, viewer]

Type mapping reference:

XSD TypeJSON Schema Type
xs:stringstring
xs:int, xs:integerinteger
xs:longinteger (format: int64)
xs:float, xs:doublenumber
xs:booleanboolean
xs:dateTimestring (format: date-time)
xs:datestring (format: date)
xs:base64Binarystring (format: byte)
xs:decimalstring (pattern-constrained)

Approach 2: Automated Tools

Several tools automate the WSDL-to-OpenAPI conversion:

APImatic Transformer

APImatic offers a cloud-based conversion service that handles WSDL-to-OpenAPI conversion. Upload your WSDL file, select OpenAPI 3.0 as the target format, and download the result. It handles complex XSD inheritance, but the output often needs manual cleanup.

wsdl-to-openapi (npm)

npm install -g wsdl-to-openapi
wsdl-to-openapi service.wsdl -o openapi.yaml

This CLI tool does a reasonable job with straightforward WSDLs but struggles with:

  • Circular type references
  • xs:any and xs:anyAttribute wildcards
  • WS-Security policy definitions
  • RPC/encoded style bindings

SoapUI + Export

SoapUI Pro can import a WSDL and export an OpenAPI spec through its API definition export feature. This is useful if you're already using SoapUI for testing.

Edge Cases That Break Automated Conversion

  • Inheritance (xs:extension). XSD supports complex type inheritance. JSON Schema uses allOf for this, but the mapping isn't always 1:1.
  • Nillable elements. XSD's nillable="true" has no direct JSON Schema equivalent. You need to decide whether to make the field nullable or optional.
  • SOAP headers. Many SOAP services pass data in SOAP headers (authentication tokens, transaction IDs). These become HTTP headers or request body fields in OpenAPI, depending on your design.
  • Overloaded operations. SOAP allows multiple operations with the same name but different message signatures. REST doesn't — you'll need to create distinct paths or use request body variations.

A Different Approach: Skip the Spec, Get Working Endpoints

If your goal isn't to document the SOAP service but to actually consume it as a REST API, converting the WSDL to an OpenAPI spec is only the first step. You still need to build the translation layer that maps REST requests to SOAP envelopes and back.

SOAPless takes a different approach. Instead of stopping at a converted specification, it gives you working REST JSON endpoints, generated OpenAPI, API Explorer output, and dashboard-side test execution from the same registered WSDL. The SOAP-to-REST translation happens at runtime, not only at the documentation layer.

Whether you convert the spec manually, use automated tools, or let a proxy handle it, the mapping concepts in this guide apply. Understanding how WSDL constructs correspond to OpenAPI constructs will help you evaluate the quality of any automated conversion output.