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.
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
.
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.
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.
Try calling the API several times in a row. The ratelimiter
should soon kick in.