Before you start with the tutorial you should finish the Getting Started guide.
In this tutorial you'll learn the basic concepts of Membrane APIs:
Membrane assigns incoming requests to APIs. The APIs process the requests and route them to backend targets. The API from the Getting Started accepted all requests from port 2000
and routed them to https://api.predic8.de
.
Now, let's make the routing more specific by adding a second API.
Go to the tutorial/rest
folder in a terminal window and start Membrane from there.
cd tutorial/rest
./service-proxy.sh
Then open the proxies.xml
file in the same folder and add a <path>
element to the API:
<api port="2000">
<path>/shop/v2/</path>
<target url="https://api.predic8.de"/>
</api>
A request 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"
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.
❯ curl localhost:2000/restnames/name.groovy?name=Pia
<?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
{"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
{
"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.
Messages flow 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.