API Management has some built-in reports for consumption and usage, but they might not fit actual requirements.

The use case in this post is a company which wants to bill their users by the number of rows returned in each call. It shows an example of custom usage reporting for API Management. The code is available here.

Overview

This is done through the following solution:

Diagram showing the layout: client -> APIM -> Event Hub -> Function -> Storage Account table -> PowerBI

  • The client is calling API Management which proxies the call to a back-end (in this example, Kubernetes. But it does not matter where the backend is).
  • When the response contains an items element, then API Management counts how many items are in array, and logs that into an event hub. This is done through this policy. It is set on an API Management product that corresponds to the offer (e.g. Pay per records returned).
  • An Azure Functions pulls each usage record and stores it into an Azure Table.
  • This table can be reported on by any solution.

Explanation

The policy is deployed at a product level, which means that anyone with a subscription to this product will get the policy applied to each call they’re making.

It assumes that APIs are somewhat standardized and always return item collections in the same field.

The policy itself contains two steps:

  1. Determine how many records are in the “items” property of the response
<set-variable name="recordsCount" value="@{
    var response = context.Response.Body.As<JObject>(preserveContent: true);
    var records = 0;
    if (response["items"] != null) {
        records = response["items"].Count();
    }
    return records;
}" />
  1. If there are items at all, send this to the event hub logger. Also set a header to a requestId value that can help track billing lines to actual calls.
<choose>
            <when condition="@((int)context.Variables["recordsCount"] > 0)">
                <log-to-eventhub logger-id="usage">@{
                    var usageRecord = new {
                        UtcDateTime = DateTime.UtcNow,
                        OperationName = context.Operation.Name,
                        UserId = context.User?.Id,
                        RequestId = context.Variables["requestId"],
                        SubscriptionId = context.Subscription?.Id,
                        RecordCount = context.Variables["recordsCount"]
                    };
                    return JsonConvert.SerializeObject(usageRecord);
                }</log-to-eventhub>
                <set-header name="x-billed-request-id" exists-action="override">
                    <value>@((string)context.Variables["requestId"])</value>
                </set-header>
            </when>
        </choose>

The Azure Function contains only one ReceiveUsageRecord function mapped to the Event Hub that saves all records to table storage.

Deployment

Provisioning

Use provision.sh to create the Azure resources in your subscription. It will create:

  • a Resource Group
  • a StorageAccount to store the usage information
  • an EventHubNamespace and an event hub
  • a function app, deploy it, and configure it to point to the eventhub and storage account that just got created.

Example application

The sample application can get deployed on a kubernetes cluster using template bounce.yaml, using command kubectl apply -f bounce.yaml.

This will create a service and a deployment containing one pod on the Kubernetes cluster you’re currently targeting.

API management setup

  1. Enable access to APIM REST API and grab a key.

  2. Create an event-hub logger called usage.

    Use the following request:

     PUT https://YOUR_APIM_NAME.management.azure-api.net/loggers/usage?api-version=2017-03-01
     Authorization: SharedAccessSignature fsdfsfsdfsdfsdfs
     Content-type: application/json
    
     {
     "loggerType" : "AzureEventHub",
     "description" : "-",
     "credentials" : {
         "name" : "usage",
         "connectionString" : "Endpoint=sb://YOUR_CONNECTION_STRING_TO_EVENT_HUB"
         }
     }
    
  3. Create a product and set the policy to the content of policy.xml.

  4. Create an API and point it to the sample application.

  5. Add the API to the product.

  6. Call the API with a subscription to this product, usage information should get sent to Event Hubs.