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.
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).
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
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.
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.
<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.
<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>
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 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.
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
s2 are the respective namespace prefixes of the namespaces in which the types existed in the original WSDL.
<message name="GetMessageRequest"> <part name="messageId" type="s1:MessageIdentificationInfo"/> </message> <message name="GetMessageResponse"> <part name="message" type="s2:Message"/> </message>
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.
<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>
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
…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.
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.
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