loading...

Codeless caching using Azure API management

mkokabi profile image Mohsen Kokabi ・4 min read

Let start by creating a simple Asp.net core api. This service is going to return a catalog in hierarchical structure.
The source data is flattened and could be coming from a repository but for now it's hard coded:

public class Category
{
    public string Key { get; set; }
    public string Label { get; set; }
    public string ParentCategory { get; set; }
}

private static readonly Category[] Categories = new[]
{
    new Category {Key = "automative", Label="Automative"},
    new Category {Key = "book", Label="Books"},
    new Category {Key = "fashion", Label="Clothing, Shoes & Accessories"},
    new Category {Key = "fashion-womens", Label="Women", ParentCategory = "fashion"},
    new Category {Key = "fashion-mens", Label="Men", ParentCategory = "fashion"},
    new Category {Key = "fashion-baby", Label="Baby", ParentCategory = "fashion"},
    new Category {Key = "electronic", Label="Electronic"},
    new Category {Key = "electronic-mobile", Label="Mobile", ParentCategory = "electronic"},
    new Category {Key = "electronic-mobile-accessories", Label="Accessories", ParentCategory = "electronic-mobile"},
    new Category {Key = "electronic-computer", Label="Computer", ParentCategory = "electronic"},
};

The output structure is hierarchical:

public class CategoryViewModel
{
    [JsonPropertyName("id")]
    public string Key { get; set; }
    [JsonPropertyName("name")]
    public string Label { get; set; }
    public List<CategoryViewModel> Children { get; set; }
}

The API would return the Json like:

[
  {"id":"automative","name":"Automative"},
  {"id":"book","name":"Books"},
  {"id":"fashion","name":"Clothing, Shoes & Accessories",
   "children":
   [
     {"id":"fashion-womens","name":"Women"},
     {"id":"fashion-mens","name":"Men"},
     {"id":"fashion-baby","name":"Baby"}
  ]},
  {"id":"electronic","name":"Electronic",
   "children":
   [
     {"id":"electronic-mobile","name":"Mobile",
      "children":
      [
        {"id":"electronic-mobile-accessories","name":"Accessories"}
      ]},
      {"id":"electronic-computer","name":"Computer"}
   ]
  }
]

I have added the swagger (The UI was not needed for this sample) and then published the API to Azure.

Creating Azure API management

The first step of creating an API management resource is straight forward but it's very time taking.
Then we would be with an Echo API
image01
The next step is adding our API. All we need is the URL to our Open API json.
image02
Then we would land on Design tab page.
image03
The main 4 areas here are Frontend, Inbound, Outbound and Backend. The arrows show the flow of processing the request.
Before being able to test our API we need to define the Backend. Click on the pen icon next to the HTTP(s) endpoint. Here, select the override and enter the service URL and hit Save
image04

Now we can test the API.
image05

The result after clicking on Send should be like:
image06

If we go back to Design and click on </> on Backend box (or on any other box), it would show the Policies for all the steps:

<policies>
    <inbound>
        <base />
        <set-backend-service base-url="https://catalogservicetest.azurewebsites.net/" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

The change that we made (defining the back end service) is stored here.

Caching

Let's get back to the the designer and click on + Add Policy on Inbound area.
From the available policies for inbound select the Cache
AddInBound
For simple cases we can specify just a time
CahceBasic
while for more advanced settings we can select Full
CahceFull

Again after saving our changes we can review them in the policies panel:

<policies>
    <inbound>
        <base />
        <set-backend-service base-url="https://catalogservicetest.azurewebsites.net/" />
        <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <cache-store duration="300" />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

As we can see the changes are in both areas: inbound and outbound.

CORS

To be able to call our API from javascript we need to allow our origin. For this sample we are going to allow our localhost, all methods, all headers, etc.
CORS
Now our policy would be like:

<policies>
    <inbound>
        <base />
        <set-backend-service base-url="https://catalogservicetest.azurewebsites.net/" />
        <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none" />
        <cors>
            <allowed-origins>
                <origin>http://localhost:3000/</origin>
            </allowed-origins>
            <allowed-methods>
                <method>*</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
            </allowed-headers>
            <expose-headers>
                <header>*</header>
            </expose-headers>
        </cors>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <cache-store duration="300" />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Subscription

While we can disable this feature using the "Subscription required" checkbox in the Settings tab page of the API, but we want to quickly demonstrate this feature.
Go to the Subscription panel and create a new subscription:
Subscription

Get the subscription key:
Subscription

and make sure in your code you are passing it in a header. The default header is Ocp-Apim-Subscription-Key but it could be defined in the Settings and it can be even passed as a query parameter which by default is subscription-key.
SubscriptionSettings

The code would be like:

  const requestOptions = {
    method: "GET",
    headers: {
      "Ocp-Apim-Subscription-Key": `${process.env.REACT_APP_BACKEND_API_SUBSCRIPTION_KEY}`
    }
  };

  useEffect(() => {
    fetch(`${process.env.REACT_APP_BACKEND_API_URL}/categories`,
    requestOptions)
    .then(receviedData => receviedData.text()
    .then(text => setTreeData(JSON.parse(text))));
  }, []);

The end result would look like:
Final

Source code is available at (https://github.com/mkokabi/apigateway)

Posted on by:

Discussion

markdown guide