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-generatorproduce 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 Concept | OpenAPI 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 header | Not needed (path-based routing) |
| SOAP fault | Error 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 Type | JSON Schema Type |
|---|---|
xs:string | string |
xs:int, xs:integer | integer |
xs:long | integer (format: int64) |
xs:float, xs:double | number |
xs:boolean | boolean |
xs:dateTime | string (format: date-time) |
xs:date | string (format: date) |
xs:base64Binary | string (format: byte) |
xs:decimal | string (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:anyandxs:anyAttributewildcards- 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 usesallOffor 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.