Anthony Chu Contact Me

RESTful APIs and Swagger (OpenAPI) in Azure Functions

Monday, December 26, 2016

Azure Functions doesn't have formal support for exposing Swagger (OpenAPI) specifications yet. But since it's built on top of Azure App Service, we can create Swagger metadata manually and use API Apps features such as API Metadata to light up tooling in Azure and Visual Studio.

Today, we'll look at how to create a RESTful API in Azure Functions and expose Swagger metadata for it. We'll then look at different ways of consuming the Swagger metadata.

Building an API in Azure Functions

It's really easy to build RESTful APIs with Azure Functions. One of the features that makes this possible is its rich support for routing templates. Using routing templates, we have full control over the routes and HTTP methods that each function will respond to.

Route prefix

By default, Azure Functions uses api as its route prefix. This means that HTTP triggered functions have the route /api/function-name. If we want to customize the prefix, we can edit host.json in the script root.

{
    "http": {
        "routePrefix": "services"
    }
}

Routes

Most RESTful APIs use the same routes for interacting with the same resource, using the HTTP method to determine the action to be taken. For instance, GET fetches a resource and PUT can be used for updating it.

To do this with Azure Functions, we create a different function for each HTTP method but give them the same route. We can set each function's route in its Integrate tab in the Azure Functions portal.

Azure Functions Routing

In the above application, we have have a function for GET and a function for POST to the same route (v1/users/{userId}/events).

We can also do the same in function.json.

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "name": "event",
      "type": "httpTrigger",
      "direction": "in",
      "route": "v1/users/{userId}/events",
      "methods": [
        "post"
      ]
    }
}

Creating a Swagger definition

Now that we have our API functional and with the desired routing, we can add a Swagger specification for it.

Swagger Editor

There's no automatic generation of Swagger in Azure Functions yet; so we will have to create the Swagger document manually. This is fairly straight-forward using the Swagger Editor at editor.swagger.io. We can start from the sample and edit the YAML to describe our Azure Functions API. When we're done, we can download the Swagger file in JSON using the File menu.

Swagger Editor

Returning Swagger definition from Azure Functions

Now that we have the Swagger file, we have to serve it from Azure Functions. To do this, we can create a function that serves this file. A few months ago, I wrote about how to return HTML files from Azure Functions. We'll use the same mechanism for the Swagger file.

Create a C# HTTP triggered function and add this code. Also save the swagger file with the function. In my example, my function is called EventsSwagger and the file is swagger.json.

using System.Net;
using System.Net.Http.Headers;
using System.IO;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(Path.Combine(GetScriptPath(), 
        @"EventsSwagger\swagger.json"), FileMode.Open);
    response.Content = new StreamContent(stream);
    response.Content.Headers.ContentType = 
        new MediaTypeHeaderValue("application/json");
    return response;
}

private static string GetScriptPath()
    => Path.Combine(GetEnvironmentVariable("HOME"), @"site\wwwroot");

private static string GetEnvironmentVariable(string name)
    => System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);

Now if we hit the URL, it should return the contents of the Swagger file.

Swagger UI and CORS

Having the API return Swagger metadata enables a few things. One use is Swagger UI, which generates API documentation from the metadata and provides an UI that allows us to interact with the API.

Swagger UI can be downloaded from GitHub. But there's a demo hosted at petstore.swagger.io. We can open it and enter the URL to our Swagger file in the box up top to load Swagger for our API.

Because Swagger UI downloads the Swagger file from another domain using JavaScript, it won't work until we enable CORS. This is simple to do in Azure Functions. In the function app's CORS settings, add Swagger UI's origin. In this case, it's http://petstore.swagger.io.

CORS

Now Swagger UI is able to load our Swagger file.

Swagger UI

If we expand an API operation, we can use the UI to test it right from the browser.

Consuming Swagger from Logic Apps

Another place that can take advantage of our Swagger metadata is Azure Logic Apps. Normally, for Logic Apps to integrate with Azure Functions, the function app must contain HTTP Webhook functions. This means the API we created does not automatically work with Logic Apps. But thanks to Swagger, that's not a problem.

In our Logic App, we can add a step called "HTTP + Swagger". That step takes a URL to a Swagger file. When we enter the URL, we get a list of operations supported by our Azure Functions API (we may have to add a CORS origin for https://ema.hosting.portal.azure.net for this to work in the Logic Apps designer).

Logic Apps

Select an operation and the UI automatically prompts us for the information needed to call it. In this example, we are triggering the Logic App when a Salesforce order is created. The fields from the Salesforce order object are automatically available for us to use in our API call.

Logic Apps

Visual Studio client generation

One last place where Swagger is useful is for generating clients for our API. Visual Studio can do this automatically for C# applications.

Visual Studio automatically discovers API Apps in our Azure account. In order for it to discover our Azure Function app, we have to set the app's API Metadata.

API Metadata

Now, in any C# project in Visual Studio, we can right click in Solution Explorer and select Add -> REST API Client. In the dialog box, click Select Azure Asset. We should be able to locate our function app. Selecting it will load its Swagger URL. Click OK to generate the API client.

generating client

When the API client is generated, we can use it to call our API:

Using the client