REST API Gateway Tutorial

This tutorial guides you through setting up routing, handling request-response flows, and enhancing security with plugins in Membrane API Gateway.

Prerequisites

Before you begin, complete the Getting Started Guide.

Step 1: Routing

Membrane routes incoming requests to backend targets. The example from Getting Started routes requests from localhost:2000 to https://api.predic8.de.

Now, we’ll make routing more specific by adding a second API.

cd membrane-api-gateway-XXX
cd tutorial/rest
./membrane.sh

Modify proxies.xml in the conf/ folder and add a <path> element to the API:

<api port="2000">
    <path>/shop/v2/</path>
    <target url="https://api.predic8.de"/>
</api>

Requests to http://localhost:2000/shop/v2/ will still work. However, if the path does not match, an error message will be returned.

curl localhost:2000
{
"type" : "http://membrane-api.io/error/gateway",
"title" : "This request was not accepted by Membrane. Please check HTTP method and path."
}

Next add a second API on the same port 2000 with a different path.

<api port="2000">
    <path>/shop</path>
    <target url="https://api.predic8.de" />
</api>
    
<api port="2000">
    <path>/restnames</path>
    <target url="https://api.predic8.de" />
</api>

Requests will now be routed to different backends depending on the path. The following requests should be routed accordingly:

curl localhost:2000/shop/v2/
curl "localhost:2000/restnames/name.groovy?name=Pia"

Step 2: Adding Behavior - XML to JSON Transformation

An API can take control when a request or response is flowing through it. By adding functionality, you can change the behavior of an API and add features like authentication or logging.

The second API we added in Step 1 returns XML. Calling:

curl localhost:2000/restnames/name.groovy?name=Pia

will return:

<?xml version='1.0' encoding='UTF-8>
    <restnames>
    <nameinfo>
    <name>Pia</name>
    <countries>
        <country href="http://localhost:2000/restnames/namesincountry.groovy?country=Netherlands">Netherlands</country>
        <country href="http://localhost:2000/restnames/namesincountry.groovy?country=Austria">Austria</country>
        <country href="http://localhost:2000/restnames/namesincountry.groovy?country=Sweden">Sweden</country>
        ...
    </countries>
    <gender>female first name</gender>
    <male>false</male>
    <female>true</female>
    </nameinfo>
</restnames>

To transform the XML response body into JSON, add the xml2Json plugin to the restnames API.

<api port="2000">
    <path>/restnames</path>
    <xml2Json/>
    <target url="https://api.predic8.de"/>
</api>

Call the API again:

curl localhost:2000/restnames/name.groovy?name=Pia

now you'll get:

{"restnames":{"nameinfo":{"gender":"female first name","name":"Pia","countries":{"country":[{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Netherlands","content":"Netherlands"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Austria","content":"Austria"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Sweden","content":"Sweden"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Belgium","content":"Belgium"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Frisia","content":"Frisia"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Norway","content":"Norway"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Finland","content":"Finland"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Denmark","content":"Denmark"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Italy","content":"Italy"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Swiss","content":"Swiss"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Germany","content":"Germany"},{"href":"http://localhost:2000/restnames/namesincountry.groovy?country=Spain","content":"Spain"}]},"female":true,"male":false}}}

That looks much better. However, to make the API more developer-friendly, let's format the JSON. Add the beautifier plugin before the xml2Json plugin. We'll discover shortly why the beautifier must come before the xml2Json.

<api port="2000">
    <path>/restnames</path>
    <beautifier/>
    <xml2Json/> 
    <target url="https://api.predic8.de"/>
</api>

Now the JSON of the response should be formatted:

curl localhost:2000/restnames/name.groovy?name=Pia

like the output below:

{
    "restnames" : {
    "nameinfo" : {
        "gender" : "female first name",
        "name" : "Pia",
        "countries" : {
        "country" : [ {
            "href" : "http://localhost:2000/restnames/namesincountry.groovy?country=Netherlands",
            "content" : "Netherlands"
        }, {
            "href" : "http://localhost:2000/restnames/namesincountry.groovy?country=Austria",
            "content" : "Austria"
        }, {
            "href" : "http://localhost:2000/restnames/namesincountry.groovy?country=Sweden",
            "content" : "Sweden"
        },
        ...
        ]
        },
        "female" : true,
        "male" : false
    }
    }
}

The xml2Json and beautifier plugin are just examples. There are more plugins available, such as OAuth2, rate limiting, or load balancing.

Step 3: Optimizing Request & Response Flow

Messages pass through a request and response flow. In Step 2 of the tutorial, we added the beautifier and xml2Json plugins to the flow. In this part of the tutorial we'll learn how to position plugins within the flow.

Open the admin console at http://localhost:9000 in your browser.

Console with services

Click on /restnames:2000, and you'll see the flow for the API. A request is received by the listener, then it flows first through the Beautifier plugin and then the xml2Json plugin. After that the request is sent to the target backend. The response flows from the target up in the opposite way, through the xml2Json and then the beautifier.

Flow

In this case, we want the two plugins in the response flow only. To achieve this, wrap the plugins with a response element.

<api port="2000">
    <path>/restnames</path>
    <response>
        <beautifier/> 
        <xml2Json/>
    </response> 
    <target url="https://api.predic8.de"/>
</api>

Then save the proxies.xml file and reload the browser.

Response flow

Now, let's add the rateLimiter plugin to our API.

<api port="2000">
    <path>/restnames</path>
    <rateLimiter requestLimit="3" requestLimitDuration="PT30S"/>
    <response> 
        <beautifier/> 
        <xml2Json/>
    </response> 
    <target url="https://api.predic8.de"/>
</api>

Take a look at the admin console again. The ratelimiter plugin only makes sense in the requests flow, so it automatically positions itself there.

Flow with rate limiter

Try calling the API several times in a row. The ratelimiter should soon kick in.