In this episode of our WSO2 tutorial: Exposing REST-resources through an API gateway provides a challenge when the resource contains hyperlinks to other resources. The linked resources need to be accessible through the gateway. Hyperlinks need to point to the API gateway using the correct URL. This post describes how this can be done in WSO2 API Manager.
Resources and hyperlinks
The API Manager from WSO2, part of the open source middleware platform for integration solutions, provides a gateway to your REST-style resources. It provides security, throttling, monitoring and other mediations. An interesting aspect of REST-style APIs is the use of hyperlinks to other resources.
Let’s assume an API with the following attributes:
- The API is implemented by an internal application and the consumer accesses all resources through the API Manager.
- The consumer retrieves a resource and the resource representation contains hyperlinks to other resources.
- Since the resources are provided by an internal API implementation, the hyperlinks are internal locations. These locations are not directly accessible by the consumer. This is quite common. The URLs of the resources could be absolute URLs containing internal hostnames (e.g. “http://myserver/student/1”) or the URI-context can differ from what is defined on the gateway (e.g. “/myapi/student/1” versus “/students/1”).
To provide hyperlinks to the consumer that can be accessed through the gateway, we need to transform the hyperlinks to externally accessible URLs.
Example
Let’s provide an example. This example will be used in the remainder of the post.
A university want to provide an API for retrieving information about available courses. The API provides a GET method to retrieve a list of all courses:
“GET /courses”
The university decided to use the HAL JSON format. If you are unfamiliar with HAL (we are not talking about the computer in Kubrick’s A Space Odyssey), HAL is a simple format that gives a consistent and easy way to hyperlink between resources in your API.
A possible response to this request is shown in figure 1.
Figure 1: the “courses” resource
The example response message contains a list of 2 courses. For each course we see the ID and the name of the course. In addition, the resource also contains hyperlinks. At the top there is a hyperlinks pointing to this resource (“self”) and, within each individual course object, we also have a link (“self”) pointing to a resource containing the full information on the particular course.
The university is going to expose this API using the WSO2 API Manager. The external URL corresponding to the above resource is going to be “http://www.someuniversity.com/catalog/courses”. The individual course is made accessible through “http://www.someuniversity.com/catalog/course/{id}”. Where {id} is a placeholder for the ID of the course.
For this example, we assume that the host “server1” is not accessible directly by the consumer. What happens when this API is exposed on the gateway? The consumer receives hyperlinks that the consumer cannot connect to! This will be fixed in the solution that follows.
Implementing the API on WSO2
To implement the API on the WSO2 API Manager we follow the standard process. See for more information the tutorial in the API Manager documentation. This is an example of what it could look like:
But now the question arises, how do we tell the API Manager to transform the URL’s to the correct format. E.g.:
Backend URL | Exposed URL |
http://server1/courses | http://www.someuniversity.com/catalog/courses |
http://server1/course/1 | http://www.someuniversity.com/catalog/course/1 |
For this functionality it is clear that the API Manager needs to perform a transformation of the response message.
Adding custom logic to an API is done through the use of custom sequences. In our case we will implement a custom sequence that is used on the out flow of the API.
The custom sequence will use an XSLT transformation that looks at every hyperlink in the message and transforms each to the required format.
You might think…but we are sending JSON. how can we do an XSLT transform on a JSON?
For this it is good to know that, as a message flows through the gateway, the WSO2 API Manager uses an internal canonical XML representation of each message (everything becomes a soap message since the gateway is an ESB by itself, the WSO2 ESB). And because of that we can easily execute a XSLT against it.
What do we need? We want to implement a flexible solution:
- Each backend API could have a different backend hostname or URL convention
- It should be easy to add and change transformations without deploying a new version of the API
We need:
- One XML file that holds all the URL transformation rules
- One XSLT file that performs transformation
- The custom sequence itself
Transformation rules file
In the XSLT we plan to use the “replace” XPath function. This function allows regular expressions to find and replace a section of text in a node. This is exactly what we need. The “replace” function takes three parameters. The first is the node to apply the transformation to, the second is the regular expression to find the test to replace and the third is the text to replace it with.
Our transformation rules file looks like:
Figure 2: Transformation rules XML file
The file contains a list of rules. Each rule contains two elements: the regular expression to match against and the string to replace it with.
Note that our example rule is very simple. There is only one rule and there is no regular-expression logic required because we can search for an exact string to replace. In case you have more complex rules, or need to exchange several parts, you will need to tinker a bit with this.
XSLT file
Before we dive into creating the XSLT file we need to think about the logic a little bit.
The XSLT needs to take two source files, the message and the transformation rules, and combine them. In XSLT there are multiple options available to do this. Normally, we could use a XSLT parameter to pass in the transformation rules XML or we can use the “document” XPath function to point to the file on the file-system. Unfortunately, both are not available when running an XSLT inside a mediation flow in WSO2. Perhaps this will change in the future but for now we need to work around this.
To work around this limitation, we will take the message and inject all the transformation rules into the message. The resulting message now has both the original message as well as all the transformation rules. The XSLT will then take this new message, apply the rules and filter out the transformation rules to form a proper output message.
The resulting XSLT is shown in figure 3.
Figure 3: XSLT file
The XSLT is an identity template that copies every element in the source XML with the exception of the hyperlinks (“href” elements) and the transformation rules that were injected into the message.
Custom out-sequence
The steps in the out-sequence flow are:
- Get the transformation rules file from the repository
- Inject the rules into the message as a sibling of the JSON object
- Apply the XSLT file
The visual flow is shown in figure 4. The XML source you can see in figure 5.
Figure 4: Out-sequence flow
Figure 5: Out-sequence source file
Bringing it together
All these three artifacts need to be uploaded to the registry of the WSO2 API Manager. See the table here where the files should go. All locations except the sequence are arbitrary.
Artifact | Registry location |
Transformation rules file | /_system/governance/mappings/hal-rewrite-rules.xml |
XSLT transformation | /_system/governance/xslt/apply-rewrite-rules.xslt |
Custom sequence | /_system/governance/apimgt/customsequences/out/HALURLRewrite-Out.xml |
The one things that remains is that, to activate the custom sequence on the API, it needs to be selected as a custom out-sequence in the API Publisher UI and redeployed. This is a one-time action. Since the gateway is an ESB this sequence will be executed after the message comes back from the backend and before it goes to the client.
Go to the API Publisher and edit the API. In the “Implement” step find the section called “Message Mediation Policies” and select the “HALURLRewrite-Out” flow in the “Out Flow” drop-down list as shown here:
We can now test the API using CURL:
The output is a JSON response that looks like the one in figure 6.
Note that we used the “Make this the Default Version” option in the API Publisher to allow a short URL. Otherwise the URL would be http://localhost:8280/catalog/1.0.0/courses.
Figure 6: The JSON response
Additional notes
- We used the excellent WireMock to simulate the backend API. See: http://wiremock.org
- The three files (transformation XML, XSLT and sequence) can be uploaded to the registry manually but they can also be created using WSO2 Developer Studio and deployed as a CAR file to the API Manager.
Special thanks to Rob Blaauboer for his contribution to this blog.
WSO2TORIALS help you to change, update or improve WSO2 products and are based on our experiences with the products. WSO2TORIALS will guide you step by step with minimal knowledge required. |