REST API Tutorial

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:

Step 1: Routing

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"

Step 2: Adding Behaviour - 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.

❯ 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.

Step 3: Request & Response Flow

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.

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.