Faria Rehman December 20, 2018
API Transformer Recipes

This blog is the second part of the series called “API Transformer Recipes”. The series aims to highlight numerous ways in which developers can integrate API Transformer into their workflow in order to gain access to a wide range of tools and frameworks. Hopefully, it will help eliminate any assumptions that they have about being restricted to a particular set of tools just because they use a certain API specification format.

Back in 2017, when we launched support for WSDL 1.1 in API Transformer, it was not anticipated that a large number of people will transform from files of this format. Mostly because WSDL 1.1 is designed exclusively for SOAP services while the supported output formats mainly describe RESTful services. However, the increasing number of people converting WSDL files on API Transformer made us think twice and compelled us to study this case more deeply. I will be sharing the findings of that in this blog. If you are a SOAP user looking to migrate to REST, I will also be discussing some ways to help you get started today.

Number of WSDL conversions t
Number of WSDL conversions to other formats that support REST (Jan 2017 — Nov 2018)

 

SOAP or REST: What is the preferred choice and why?

The choice between SOAP and REST depends mainly on the requirements of the application being developed. For larger enterprise-level applications, that demand standardization and rely heavily on security, SOAP is still preferred by many. REST, on the other hand, is quickly becoming the popular choice for mobile and web applications where higher performance and lesser complexity takes more priority. It has a smaller learning curve which reduces the time it takes for developers to work on, document, and maintain such applications. In most cases, REST relies on JSON for data exchange which has lesser overhead involved as compared to dealing with the highly verbose (and often painfully complex) XML in SOAP. JSON also means better support for browser clients. REST reads can be cached for better performance and scalability.

Today, with the ever-increasing number of web and mobile applications, the APIs being exposed are largely based on REST+JSON. Such APIs change all the time as businesses adapt to new requirements and REST provides much-needed flexibility. Using SOAP in such cases, with its specific contractual agreements, is likely to add only unnecessary complexity. Due to this, even the developers who have had their services exposed using SOAP APIs are now looking to make them RESTful.

Will an adapter layer or a proxy service let you REST?

If your SOAP service works over HTTP, some quick solutions to expose your SOAP service as a REST service are:

1) Add an adapter layer on top of the SOAP service

2) Add a proxy service for calling the SOAP service.

While I won’t be going into the depths of these, both solutions suggested above will have one thing in common: Conversion of any incoming REST requests to SOAP compatible requests (e.g. wrapping the request in a SOAP envelope) and conversion of any outgoing SOAP responses to REST compatible responses (e.g. converting XML responses to JSON).

Handling REST requests with a converter
Handling REST requests with a converter

And while these solutions are a good start and will let you get your system into production in no time, they are not very likely to be scalable in the long run. Eventually, a situation will arise when you will have no other choice but to refactor or rewrite your SOAP service using REST.

Start RESTing with API Transformer

Start RESTing with API Transformer

So, if the adapter/proxy solution does not work for you and you are looking for a more effective and long-lasting solution, you will have to rethink your model and start building up from there. Sure, it is likely to take more time and would require a lot more manual work but hey, the fruits of hard work are sweet, aren’t they?

Okay, let’s not despair just yet. API Transformer has got you covered (at least for the most part). We can help make your task a little less daunting. How? We let you convert your WSDL files to OpenAPI/Swagger and other formats that support REST. This would give you a head start on the model that you need to work on. Below, I’ll dive into this a little deeper so you get a better idea of what I mean.

WSDL

This is a file associated with SOAP often described as a contract between the service provider and its consumer. It provides a complete definition of how the service works including fine-grain details of all elements and attributes involved. It also helps dictate restrictions like the order in which the elements must appear. Many tools exist that let you generate method stubs in almost any language if you have the WSDL file with you.

Formats that support REST

A common question asked is: Is there a WSDL like format for REST? Truth is, there is no one format that describes all kinds of RESTful APIs. Many formats exist that attempt to cover as many aspects as possible. Some of the well-known ones include OpenAPI/Swagger, API Blueprint, RAML, etc. If you are able to get your hands on any one of these, you can benefit from a wide range of tools and frameworks that lets you mock, test APIs as well as auto-generate client/server code.

From WSDL to a more RESTful model with API Transformer

As mentioned earlier, API Transformer helps you transform a WSDL file associated with a SOAP service to any of the popular REST-supporting formats. I converted one such file to OpenAPI/Swagger v2.0. The conversion process and output are analyzed below. If you are interested to see the complete files, you can find them here.

1. Service Information

During the conversion, service details like the name, documentation, and location address are extracted from the WSDL and placed in the relevant Swagger components.

WSDL

<service name="HelloService">
  <documentation>WSDL File for HelloService</documentation>
  <port binding="tns:Hello_Binding" name="Hello_Port">
     <soap:address location="http://www.examples.com/MessagingService/" />
  </port>
</service>
swagger: '2.0'
info:
  version: '1.0'
  title: HelloService
  description: WSDL File for HelloService
host: www.examples.com
basePath: /MessagingService/
schemes:
- http

2. WSDL Operation vs Swagger Operation

WSDL operations are defined in an abstract way inside the port types and their concrete details are provided in the bindings. When mapping these operations to Swagger operations, we try to utilize as much information as possible from both port types and bindings.

WSDL:

<portType name="Hello_PortType">
    <operation name="getMessage">
       <input message="tns:GetMessageRequest"/>
       <output message="tns:GetMessageResponse"/>
    </operation>
</portType>
<binding name="Hello_Binding" type="tns:Hello_PortType">
    <soap:binding style="document"
       transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="getMessage">
       <soap:operation soapAction="getMessage"/>
       <input>
          <soap:body use="literal"/>
       </input>    
       <output>
          <soap:body use="literal"/>
       </output>
    </operation>
 </binding>

OpenAPI/Swagger:

paths:
  /getMessage:
    post:
      summary: getMessage
      tags:
      - Hello_Binding
      operationId: GetMessagePost
      produces:
      - application/json
      parameters:
      - name: Body
        in: body
        required: true
        schema:
          $ref: '#/definitions/GetMessageRequest'
      responses:
        200:
          description: ''
          schema:
            $ref: '#/definitions/GetMessageResponse'

The mapping is not perfect, however:

a. According to REST principles, a resource’s relative path should ideally indicate the resource on which the CRUD operations are to be performed. For the conversion from WSDL, this path is extracted from the SOAP operation’s name. However, since SOAP is function-driven, the operation names in WSDL are always function names that don’t always result in the ideal resource path. In the example above, therefore, the resource path /getMessage should have been /message (message being the resource here) with the HTTP verb as being sufficient to indicate the action to be performed on the resource (the get keyword in the path being unnecessary, therefore).

b. For the conversion, we assume that all WSDL operations use POST by default unless the HTTP method is explicitly specified through HTTP bindings in the WSDL file. This is because, in all other cases, detecting the correct CRUD operation from WSDL is not directly possible. The output, therefore, may not indicate the ideal HTTP method of the operation e.g. the GetMessagePost Swagger operation is only retrieving an object of the message resource without changing the resource in any way. Based on this, the operation should be using the GET method instead of POST. You will, therefore, be required to manually identify the correct method for all operations and change it in the output.

c. REST is designed largely to work over HTTP while SOAP is capable of supporting other protocols as well. Any concrete binding information about other protocols will be lost during the transformation because of incompatibility with RESTful formats e.g. in the above conversion, any information related to the SOAP transport mechanism, binding style and body encoding is lost in the output.

3. Namespaces

There is no concept of namespaces in REST whereas WSDL relies heavily on them:

<definitions name="HelloService"
   targetNamespace="http://www.examples.com/wsdl/HelloService.wsdl"
   xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns="http://www.examples.com/wsdl/HelloService.wsdl"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:s1="http://www.examples.com/schema1"
   xmlns:s2="http://www.examples.com/schema2">
.
.
</definitions>

In case of types from schemas of different namespaces, we try to preserve some of the namespacing context e.g. in the output the types are named s1_MessageIdentificationInfo and s2_Message where s1 and s2 are the respective namespace prefixes of the namespaces in which the types existed in the original WSDL.

WSDL:

<message name="GetMessageRequest">
    <part name="messageId" type="s1:MessageIdentificationInfo"/>
</message>
<message name="GetMessageResponse">
    <part name="message" type="s2:Message"/>
</message>

OpenAPI/Swagger:

GetMessageRequest:
  title: GetMessageRequest
  type: object
  properties:
    messageId:
      $ref: '#/definitions/s1_MessageIdentificationInfo'
  required:
  - messageId
GetMessageResponse:
  title: GetMessageResponse
  type: object
  properties:
    message:
      $ref: '#/definitions/s2_Message'
  required:
  - message

4. XML Schema to JSON Schemas

The conversion involves mapping of XML schema content to JSON schemas (or a subset of JSON schemas but that is irrelevant here). Since XML and JSON are not fully compatible with each other, some information will not be fully translated e.g. JSON does not support attributes and due to this the messageId attribute of MessageIdentificationInfo is loaded as a normal field in the output with nothing to indicate its nature as an attribute.

WSDL:

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.examples.com/schema1" elementFormDefault="qualified">
    <element name="MessageIdentificationInfo">
        <complexType>
            <sequence>
                <element name="senderName" type="xsd:string"/>
                <element name="recipientName" type="xsd:string"/>
            </sequence>                
            <attribute name="messageId" type="xsd:string"
              use="required"/>
        </complexType>
    </element>
</schema>

OpenAPI/Swagger:

s1_MessageIdentificationInfo:
  title: s1_MessageIdentificationInfo
  type: object
  properties:
    messageId:
      type: string
    senderName:
      type: string
    recipientName:
      type: string
  required:
  - messageId
  - senderName
  - recipientName

Takeaways before you can fully REST

As you can see, the conversion isn’t the only step you need to get up and running with a RESTful service because it can only do so much. It provides you with a rough model of what your service can look like which will require additional work before it can be considered fully RESTful. For example, you will have to manually identify the resources involved in your service as well as the CRUD operations that need to be performed on them besides POST.

Kin Lane, the very famous API Evangelist, who once tried experimenting with such conversions summarizes his experience very nicely in his blog:

…I do like having tools that help me make sense of what was, and create a scaffolding for what can be. Then I just dive in and clean up, polish, and move forward as I see fit.

You will need to keep on molding your model until it attains a shape that suits your application as well as abides by the REST principles. A similar approach was also followed by some of our customers from the National Bank of Canada who were able to create RESTful models for their SOAP-based services using API Transformer.

Once you have your model ready, there are tools out there that let you generate server stubs which can ease the implementation process e.g. you can generate server stubs from Swagger Codegen with an OpenAPI/Swagger file.

Conclusion

If you are ready to make the jump from SOAP to the RESTful world, nobody is stopping you. There are plenty of ways out there to facilitate you in the process. But, don’t jump blindly! Just because everyone is doing it doesn’t mean you have to as well. Establish the need first and then work towards it.

Continue reading:
a) Part 1 of API Transformer Recipes: Enabling Postman’s Team Sharing Features for OpenAPI Users
b) Part 3 of API Transformer Recipes — Opening ways into IBM API Connect
c) Part 4 of API Transformer Recipes — Moving to GraphQL from SOAP or REST
d) Part 5 of API Transformer Recipes: The Whys and Hows of Exposing a SOAP Service Using Your REST API