wsdlopenapiapi-designtutorial

Convert WSDL to OpenAPI (Swagger) Spec: Complete 2026 Guide

SOAPless Team5 min read

If you're maintaining a SOAP service and need to document it for a team that thinks in REST and OpenAPI, converting your WSDL to an OpenAPI (Swagger) specification is a practical step forward. It bridges the gap between legacy SOAP infrastructure and modern API tooling — enabling Swagger UI documentation, client code generation, and integration with API gateways that speak OpenAPI natively.

This guide covers both manual and automated approaches, explains the mapping between SOAP/WSDL concepts and OpenAPI constructs, and highlights the edge cases that trip people up.

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.

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 converting the specification, it converts the service itself. Point it at your WSDL URL, and it generates working REST endpoints that accept JSON and return JSON — complete with an auto-generated OpenAPI spec that you can use with Swagger UI, client generators, or API gateways. The SOAP-to-REST translation happens at runtime, not at the documentation level.

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.