Taking Azure API Management For a Ride

Tags: Azure

At my day job we're going through a proof of concept with MuleSoft right now. Kicking the tires sort of thing. Our main use case is to integrate the enterprise with an API layer. And of course we're also a .NET shop. I know that Amazon API Gateway and Azure API Management are also out there and could be a more cost effective alternative. The elephant in the room is Swagger (now the Open API Initiative) and I like how the industry is consolidating around an open-source spec.

So what to do? Azure works with Swagger so that's worth looking at closely. So let's walkthrough a very simple Widget API and hosting it in the Azure API Management portal. This is an interesting exercise in and of itself but it will also serve to help with our MuleSoft investigation.

The prereqs are Visual Studio 2015 (Update 3) and the latest Azure SDK (2.9 in my case). You'll also need an Azure account either through your MSDN or otherwise.

In Visual Studio 2015 Choose File > New > Project and pick the ASP.NET Web Application. At the next window pick the Azure API App project template. Click OK to unfold the template.

You'll see that a Metadata folder with a JSON file has been added to provide support for Swagger. Also, in the App_Start folder a SwaggerConfig file has been added. This bootstraps our API discovery for us. Add this model to the Models folder:

public class Widget
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Shape { get; set; }
}

Replace the ValuesController with this controller:

public class WidgetController : ApiController
{
    [HttpGet]
    public IEnumerable<Widget> GetAll()
    {
        var items = MockDatabase.Widgets.OrderBy(w => w.Name);
        return items;
    }

    [HttpGet]
    public Widget GetWidget(int id)
    {
        return MockDatabase.Widgets
		    .FirstOrDefault(w => w.ID == id);
    }

    [HttpPost]
    public Widget Post(Widget item)
    {
        var widget = MockDatabase.Widgets
		    .FirstOrDefault(w => w.ID == item.ID);
        if (widget == null)
        {
            item.ID = MockDatabase.UniqueWidgetId;
            MockDatabase.UniqueWidgetId++;
            MockDatabase.Widgets.Add(item);
        }
        else
        {
            widget.Name = item.Name;
            widget.Shape = item.Shape;
        }

        return item;
    }

    [HttpDelete]
    public IHttpActionResult Delete(int id)
    {
        var item = MockDatabase.Widgets
		    .FirstOrDefault(w => w.ID == id);
        if (item != null)
        {
            MockDatabase.Widgets.Remove(item);
        }
        return Ok();
    }
}

public static class MockDatabase
{
    public static IList<Widget> Widgets { get; }
    public static int UniqueWidgetId = 5;

    static MockDatabase()
    {
        Widgets = new List<Widget>()
        {
            new Widget { ID = 1, Name = "Cog", Shape = "Square" },
            new Widget { ID = 2, Name = "Gear", Shape = "Round" },
            new Widget { ID = 3, Name = "Sprocket", Shape = "Octagonal" },
            new Widget { ID = 4, Name = "Pinion", Shape = "Triangular" }
        };
    }
}

Now we have a simple API that adds, deletes, and returns widgets to the consumer. Deploy the project to Azure: right-click the project and choose Publish. Choose Microsoft Azure API Apps as your publish target. The handshake to Azure will happen and then you can publish it on up to whatever resource group you choose. After a few moments you should get a new browser window with a warm fuzzy that says the API has been successfully created. Notice the URL (also in your project output) contains a random encoded value and is not human readable. This is the rough equivalent to a MuleSoft System or Process API. It's not meant to be hit directly by end users.

MuleSoft has the concept of an "Experience API" which is a layer that sits on top of lower-level process APIs. The Azure equivalent is the API Management portal. It's not yet in the new portal so you have to go to the classic view at https://manage.windowsazure.com to create it. Once in the classic portal go down the left-hand menu and click API Management. Go through the steps to create one. This takes a good 20 minutes so now's a good time to get coffee.

Ok you have coffee and it's still not done yet. :) Let's do an intermediate step while we wait. Go to the new Azure portal at https://portal.azure.com and find the widget API you published. Notice the big box under summary that says API definition. Click that. The right window opens and you should see all four operations from the WidgetController. Just above them is a link that says "Download Swagger." Click that and download the Swagger JSON file that describes our API.

Ok by now you have a brand new API Management portal. Click on the name to go to the "Get Started" screen. From here you can go to the developer portal or the publisher portal. In this case we want to go to the publisher portal. Click on APIs menu item. Notice that we have two options: add API or import API. Our API serving up widgets was already published so we want to import it here. Click Import API. Provide the JSON file from the file you just downloaded. Choose "Swagger" as your specification format. Leave the default New API radio button selected and enter "widgets" as the url suffix. Your URL should be in the format: http(s)://xxxxx.azure-api.net/widgets. This is the public facing URL for the endpoints. Finally, choose the Starter product and click Save.

Now the API portal shows your new widgets API. The API Management portal let's you set up different service level agreements (called Products) for each API. There are two out of the box: Starter and Unlimited. Starter prohibits subscribers from making more than 100 calls per week. As its name suggests Unlimited allows unlimited API access for all subscribers. You can delete these and create your own. They can be as course or as fine-grained as you like. You can also configure JSON web token (JWT) security so only your subscribers can call your API. There are many other features and I don't want to go through them all. You can see them for yourself.