Getting Metric Data from Azure API Management

The Azure API Management portal provides a useful dashboard showing number of calls to an API over time, bandwidth used, number of errors and average response time.

Viewing this information in the online dashboard is useful, but integrating it into existing dashboards and/or monitoring tools is even more powerful so – what it takes to get this data programmatically?

Not much, as it turns out!

APIM has a good set of management APIs to itself, including reporting on metrics. The first step is to enable the API Management REST API, which can be done within the security tab of the APIM admin portal –

image

Then, for my exercise, I manually created an Access Token at the bottom of the page, which I’ll use later when issuing requests to the portal. This can be done programmatically

Now that I’m able to call the management API, it is time to experiment with some requests.

The security tab showed the base Url for the management api which takes the form of

https://{servicename}.management.azure-api.net

Every request to this url must include an api- version with the current value being – 2014-02-14-preview
The request also needs to include an Authorization HTTP header with the value being the access token generated either in the portal or programmatically.

There are many entities that can be operated on using the management API, the list is published here. In this case I wanted to look at the Report entity which can be use to retrieve metrics

Using this entity I can get usage metric by time period, geographical region, user, product, api or operation. I chose to get metrics by time so I appended to my url the entity path – /reports/byTime, the requests at this stage looks like this  –

https://apiyd.management.azure-api.net/reports/byTime?api-version=2014-02-14-preview

the byTime report takes 2 additional parameters – Interval, which defines the aggregation period  and $filer which can be used to restrict the data returned., I’ve decided to aggregate data in 40 day increments and requested data from August 2014, the full request looks like this –

https://apiyd.management.azure-api.net/reports/byTime?api-version=2014-02-14-preview&interval=P40D&$filter=timestamp ge datetime’2014-08-01T00:00:00′

and the response looks like this –

image

You can see that I get two groups (there are more than 40 days between today and last August, with the relevant metrics in them.

I could also change the accept HTTP header to text/csv to receive the data in CSV format –

timestamp,interval,callCountSuccess,callCountBlocked,callCountFailed,callCountOther,callCountTotal,bandwidth,cacheHitCount,cacheMissCount,apiTimeAvg,apiTimeMin,apiTimeMax,serviceTimeAvg,serviceTimeMin,serviceTimeMax
09/10/2014 00:00:00,P40D,128,9,2,13,152,153677,18,3,422.1049578125,0.376,5620.048,399.780409375,0,5598.4203
11/29/2014 00:00:00,P40D,7,0,6,0,13,10648,0,0,171.982185714286,32.0005,612.5971,162.947842857143,19.8287,579.0369

Using Azure API Management between client and Azure Mobile Services backend

I’m working on a solution with a customer which requires placing Azure API Management (APIM) between the mobile devices and the published Azure Mobile Services (ZuMo) .net backend.

Conceptually this is fairly straight forward, given that all of the Mobile Services capabilities are exposed as Web APIs but I needed to figure out what changes might be required to the client app to support that and prove that it works.

To get started, I created an API in Azure API Management with the relevant operations in APIM (for now I focused on the default GET request for the ToDoItem table so I defined a simple GET operation in APIM with the URL template /tables/TodoItem?$filter={filter}

image

The generated windows 8 app code for the ToDo item sample includes the following code to create the MobileServiceClient instance, which points at the ZuMo URL –

        public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://travelviewer.azure-mobile.net/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56"
        );

Naturally, to hit APIM instead of ZuMo directly, this needed to be updated to point at the APIM API published, in my case  I changed it to be

        public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://apiyd.azure-api.net/travelviewer/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56"
            );

Running the application with only this change was clearly not enough, I got the following error when trying to retrieve the ToDo items from the backend (currently configured to require no authentication)

image

This was not unexpected, but I wanted to prove the point. Trusted Fiddler provided more information – I could see the request going exactly as expected –

GET https://apiyd.azure-api.net/travelviewer/tables/TodoItem?$filter=(complete%20eq%20false) HTTP/1.1

and it included the various ZUMO headers (Installation Id, application, etc.

But the response was – HTTP/1.1 401 Access Denied

With the body providing the exact details –

{ 
   "statusCode": 401, 
   "message": "Access denied due to missing subscription key. 
               Make sure to include subscription key when making 
               requests to an API." 
}

Authentication to Azure API Management (APIM) is done by providing a subscription key either as a query string parameter (‘subscription-key’) or an HTTP header (‘ocp-apim-subscription-key’) and clearly the ZuMo client does not know it needs to do that, so – how do we work around that?

The answer, I believe, is to create an HttpMessageHandler or – more specifically – a DelegatingHandler.

The MobileServiceClient takes in a third parameter which is an array of such delegates that are then given the chance to process the outgoing requests and responses flowing through the client, this is a great opportunity to inject the missing HTTP header in a central place without affecting the application’s code.

and so I created a class that inherits from System.Net.Http.DelegatingHandler

class InsertAPIMHeader : DelegatingHandler
    {
    }

and I’ve overridden the main method – ‘SendAsync’ – and in it simply added the required header to the HttpRequest (in my case – hardcoded)

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                    System.Threading.CancellationToken cancellationToken)  
{ request.Headers.Add("ocp-apim-subscription-key", "84095a7d792a47738464faae6bf950d3"); return base.SendAsync(request, cancellationToken); }

The last step is to write that into the MobileServiceClient Constructor, in my App’s App.xaml.cs I’ve added an instance of the delegate as the last parameter

public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://apiyd.azure-api.net/travelviewer/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56",
            new InsertAPIMHeader()
            );

 

Running the app again and refreshing the list of ToDo items now works. inspecting the request in Fiddler shows the request now has the APIM subscription key header

GET https://apiyd.azure-api.net/travelviewer/tables/TodoItem?$filter=(complete%20eq%20false) HTTP/1.1
X-ZUMO-FEATURES: TT,TC
X-ZUMO-INSTALLATION-ID: 226d6ea7-2979-4653-96d4-a230128719c5
X-ZUMO-APPLICATION: hmptBIjrEnAELyOgmmYPRPSOZlLpdo56
Accept: application/json
User-Agent: ZUMO/1.2 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=1.2.21001.0)
X-ZUMO-VERSION: ZUMO/1.2 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=1.2.21001.0)
ocp-apim-subscription-key: 84095a7d792a47738464faae6bf950d3
Host: apiyd.azure-api.net
Accept-Encoding: gzip

and, importantly – I actually got a result, meaning that APIM accepted the request, forwarded it to the mobile services backend and relayed the result. Success!

%d bloggers like this: