Exposing SOAP WebServices as RESTful APIs
Got a load of WebServices from your historical Service Oriented Architecture efforts? Never fear, we can turn them into RESTful APIs in a few, easy steps with API Management.
Introduction
Before the advent of RESTful APIs that took the IT world by storm, Service Oriented Architecture (SOA) was the primary approach to integrating and unlocking data and systems.
A key challenge with SOA is it’s mainly based on WebServices. WebServices, and more specifically, SOAP WebServices, are based on protocols and data formats that can be difficult to deal with by, for example, a web developer that needs to build a lightweight application to allow customers to communicate with the business.
SOA and SOAP WebServices have been around for decades now. This means that many of the digital transformation initiatives Gravitee supports have, at their core, the need to expose these legacy WebServices in a way that makes them easier to consume by modern applications, without necessarily having to throw away years of hard work and investments.
One of the common use cases that Gravitee easily helps to address, and one of the most common questions that developers and architects ask us is: how can I expose a SOAP WebService as a RESTful API?
In this article, we will show you in a few steps, how to build a simple API to expose the Calculator SOAP WebService.
Design-First Approach
For this article, we want to adopt the best possible practice in delivering an API strategy. Design-First approach delivers several benefits. But what is the Design-First approach? For a more in-depth overview, do check out Lorie Pisicchio’s blog on the subject. To keep it simple and short, we’ll start our Numbers API by designing the contract first, and only then will we move on to create the actual API.
This provides several benefits:
- It allows us to focus on what capabilities the API should provide
- We can use the contract to get early validation. Is the API easy to understand? Does it follow RESTful principles? Does it expose all the needed resources? And so forth...
- The contract can be used to mock data that can be exposed and consumed before the real API has actually been built, increasing the speed of overall delivery and reducing the time to market.
So, what is our Numbers contract? Let’s have a look at how it would appear when using Gravitee API Designer:
Now, I want to make a big disclaimer: THIS API IS NOT RESTful! As you can see, the above design defines “actions”, whilst we all know that a real RESTful API should define nouns instead.
Although this API won’t be fully REST, it will allow me to nicely expose a SOAP WebService using a simple HTTP “REST” endpoint. The beauty of using API Designer is that I was able to draft this API contract in a few minutes. I won’t dig into the details of how you can achieve this using Gravitee API Designer since this is not the main focus of this article, but you can check this article if you want more details.
Once the API design is complete, and it’s been validated by all business stakeholders and maybe by your final consumer, you’re then ready to move on and begin the next phase of the API lifecycle, the management!
I will click on “Push” at the top of the page
Select “Mocked API” to expose an API that will return, you guessed it, mock data:
And click on “Push to APIM”:
The API has now been pushed and I can now click on “View in APIM” to start managing my API.
Once in the console, you’ll notice that the API is already running:
Really cool! So you could already invoke the API but it won’t do much. What we can do at this point is to click on “PUBLISH THE API” so it will be available on the portal:
As you can see, in just a few minutes, we’ve been able to have an API up and running and published on the portal so people can start discovering it.
Defining the API Backend
Now on to the interesting part, defining the API Backend. Our SOAP web service exposes the following services:
- Add
- Divide
- Multiply
- Subtract
So how do we expose, for example, the /add endpoint so that it takes whatever input is sent to the API (in our case we’ll be using two query parameters) and transform that into a SOAP Envelope to be sent to the Calculator WebService? Let’s go step by step.
First of all, you will need to configure your API backend to be the WebService endpoint. Head to Proxy → Endpoint:
You should see a default endpoint defined. Click on the cog icon on the “default” row:
Within “Target” enter the SOAP WebService endpoint, which in our case will be http://www.dneonline.com/calculator.asmx:
Cool — the first step is done. Now any request sent to your API will be forwarded to the Calculator SOAP WebService. The problem still left to solve is the logic to transform the input into a SOAP Envelope.
REST to SOAP
To convert two query parameters (num1
and num2
) into a SOAP envelope, head to “Design”. You will see that when the contract was pushed to API Management from API Designer, flows were automatically generated for each of the resources declared in the contract.
This is cool and it will save us a lot of time. However, our API is not fully RESTful, therefore you should go ahead and remove some of the flows that are not in use:
Specifically, you can remove:
- /add/:id
- /sub/:id
- /div/:id
- /mul/:id
So the flows should look like this:
Believe it or not, we’re almost there!
Now let’s work on the /add endpoint, which allows adding two numbers passed as URL query parameters. All the others will work pretty much the same way and I will show you a cool trick so you can replicate the work across all the flows, in a very easy way. Keep reading!
The first thing you need to do is to remove the Mock policy that was generated when pushing the API from API Designer.
Next step, search for SOAP in the policy search box:
Drag and drop the Rest to SOAP Transformer policy onto the REQUEST flow
Now we need to do a couple of things;
- Determine how we want the parameter to be passed to the API
- Determine what to send to the Calculator WebService
The first point is easily addressable. As an API developer, your job is to make sure the API complies with the design, and the design states that add defines two “searchable” attributes: num1
and num2
:
Therefore our job will be to capture those two query parameters and send them to the WebService (we’ll over this shortly).
The Add WebService expects the following SOAP Envelope:
<?xml version=”1.0" encoding=”utf-8"?><soap:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=”http://www.w3.org/2001/XMLSchema" xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <Add xmlns=”http://tempuri.org/"> <intA>NUMBER HERE</intA> <intB>NUMBERE HERE</intB> </Add> </soap:Body></soap:Envelope>
Since num1
and num2
will be passed over as URL query parameters, we can use the following SOAP Envelope:
<?xml version=”1.0" encoding=”utf-8"?><soap:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=”http://www.w3.org/2001/XMLSchema" xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <Add xmlns=”http://tempuri.org/"> <intA>{#request.params[‘num1’]}</intA> <intB>{#request.params[‘num2’]}</intB> </Add> </soap:Body></soap:Envelope>
Here we are using Gravitee’s Expression Language to capture the two query parameters, and embed them into the SOAP Envelope.
Now go ahead and copy the above within the SOAP Envelope policy configuration setting:
We’re almost there… you now need to specify the SOAP Action header. This is only required if the WebService supports SOAP 1.1. Newer versions of SOAP do not require a SOAP Action header. This header tells the WebService the intent of the SOAP HTTP request. For our Calculator WebService you can use the following intent:
http://tempuri.org/Add
Specify “utf-8” as a charset. Finally, you need to enable the Strip path setting otherwise the SOAP Envelope will be sent to http://www.dneonline.com/calculator.asmx/add. So the final settings should look like this:
Now click on “deploy your API’ at the top of the screen:
And let’s try to invoke our first API endpoint:
That worked! We are able to expose the API and generate a SOAP Envelop that was sent to the WebService. Now the only problem is that the Calculator WebService is returning another SOAP Envelope. Let’s transform this into a nice JSON string instead for our Javascript developer. First of all we’ll apply an XML-JSON policy. No configuration required here!
And let’s see what happens when we invoke the API now:
Wow! With little effort we’ve already got a JSON output that looks almost like what we want. This could already be used by an application developer, but let’s simplify it so to remove any trace of the underlying SOAP WebService. You have two options, either use the Javascript or Groovy policy to generate a simple JSON string, or you can use the JSON to JSON Transformation policy to do the same. Let’s use the latter approach. Place the policy on before the XML to JSON policy:
Configure the policy with the following JOLT specification:
[ { “operation”: “shift”, “spec”: { “soap:Envelope”: { “soap:Body”: { “AddResponse”: { “AddResult”: “Result” } } } } }]
This policy will extract the value from the AddResult
object and place it at the top of the JSON string with the name Result
. Now save, publish the API and let’s test again:
Success! You’ve now created a REST API that exposes a SOAP WebService but in a much nicer and developer (and REST) friendly way. You can now leverage all the capabilities of the Gravitee platform, such as adding Plans to monetize your API, add layers of security with the out of the box policies, and even allow users to login using Multi-factor authentication (MFA) by leveraging Gravitee Access Manager!
Ooops..
Do you remember I said I was going to show you a trick how to copy policies across all the other flows, so you don’t have to redo all the (fairly similar) work? Let me show you!
First of all, head over to the Rest to SOAP Transformer policy, and click on “Duplicate”:
Now hover over the /sub flow and click on the small arrows icon that says “Compare”:
Now simply drag the policy that you duplicated to the REQUEST flow of the /sub endpoint:
Click on “Move” and the copy is done!
Conclusion
There are still a lot of organizations who depends on data and business capabilities delivered by legacy SOAP WebServices. However, technology has evolved and SOAP WebServices have proved to be extremely painful to adopt by the masses. For these reasons, organizations chose to expose them using more modern protocols like REST.
We’ve shown how Gravitee makes it very easy to unlock data and functionalities locked in legacy WebServices. It can support you in delivering the entire API lifecycle, starting from designing the contract in a visual way, to managing your API using Gravitee low-code/no-code to apply security, traffic shaping and transformation.
If you’d like to discuss the example in this post, or have other questions, come join us on the community forum.