Generating OpenAPI / Swagger definition from Azure Functions

4 minute read

When you build a regular web app in ASP.NET Core, you can easily hook bunch of tools to it in order to be able to generate OpenAPI definitions. With Azure Functions, this is slightly more complex and challenging.

At the moment there doesn’t appear to be any official release and recommended guidance form Microsoft on how-to generate OpenAPI definitions from Azure Functions. There are many contributions from the community (1, 2) which make it much easier, but I ended up hitting some incompatibilities between Function runtimes - especially lack of support for V3. Some time ago, I stumbled upon Microsoft’s OpenAPI implementation which is also used by Swashbuckle for example.

Along with that library, Microsoft has a very nice project called OpenAPI.NET.CSharpAnnotations which allows you to generate the definition from annotation XML. And guess what you can annotate? Yes, Azure Functions as well!

I decided to build a small sample in Azure Functions inspired by the Swagger Petstore sample. You can find the functioning code on my GitHub.

Basically I annotated all the methods and model objects, so that an XML definition gets generated. Along with that, I added a method which generates the OpenAPI document at run-time and serves it to consumers:

[FunctionName("swagger.json")]
public static async Task<HttpResponseMessage> RunSwagger([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
{
    var input = new OpenApiGeneratorConfig(
        annotationXmlDocuments: new List<XDocument>()
        {
            XDocument.Load(@"AzureFunctionsOpenAPIDemo.xml"),
        },
        assemblyPaths: new List<string>()
        {
            @"bin\AzureFunctionsOpenAPIDemo.dll"
        },
        openApiDocumentVersion: "V1",
        filterSetVersion: FilterSetVersion.V1
    );
    input.OpenApiInfoDescription = "This is a sample description...";

    var generator = new OpenApiGenerator();
    var openApiDocuments = generator.GenerateDocuments(
        openApiGeneratorConfig: input,
        generationDiagnostic: out GenerationDiagnostic result
    );

    return new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(openApiDocuments.First().Value.SerializeAsJson(OpenApiSpecVersion.OpenApi2_0), Encoding.UTF8, "application/json")
    };
}

You can then use this generated swagger.json file to consume it in Swagger UI, Swagger Editor, API Management or service of your choice.

Generated definition by Azure Function!

So how to get started on an existing project? First off, decide when you want to generate the definition - design-time, build-time or run-time. Obviously design-time doesn’t make much sense (because at desing-time, you make the definition even before you write your code). My sample is going with run-time, but build-time is much more suitable for use with Azure API Management for example.

Next, enable XML documentation file output in your project, either via GUI or in your .csproj file:

<PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
    <DocumentationFile>AzureFunctionsOpenAPIDemo.xml</DocumentationFile>
</PropertyGroup>

After that a new file should pop in your project folder - make sure to add it to .gitignore, since it is something that is generated and shouldn’t probably be part of your repository (I included it into the repo, so you can take a look at it online).

Then you just either create the endpoint I shown above or generate the definition at build time with this awesome DevOps extension provided by Microsoft. It does not only build the definition for you, but it also can publish it into another Git repo seamlessly, so you can run another process from that.

One thing which I miss is having an out-of-box method to convert IFormCollection to my desired model, but I am sure everyone can come up with some nice way (we use JSON for most of the things anyways in here).

All in all, I see this as the most viable solution for quick use with Azure Functions at the moment, since it is very likely that it will work with Azure Functions vNext and onwards.

Comments

Yasmine Ben

Hi Jan- Great article!

I had a question- any ideas on how to feed the JSON endpoint to the SwaggerUI as you mentioned? I only see this doc (https://docs.microsoft.com/en-us/samples/aspnet/aspnetcore.docs/getstarted-swashbuckle-aspnetcore/?tabs=visual-studio) that indicates how to feed it to the SwaggerUI when using IApplicationBuilder in my Config function in the Startup.cs file, but since I’m using Azure Functions, I only have an IFunctionsHostBuilder object which does not have UseSwagger, UseSwaggerUI, etc. defined. Any thoughts on this? I followed your tutorial and defined the “Swagger” function using DocumentGenerator and C# annotations to generate the XML and make the OpenAPIDocument object so I see the json when I visit the api/swagger endpoint but I’m stuck on the UI portion. If I can’t really find anything on the internet for this half.

Thanks again :)

Jan Hajek

Hey Yasmine, I haven’t got the Swagger UI working in this case. I usually visualize the definition via https://editor.swagger.io/. There have been projects to directly embed Swagger UI and load it from within the Azure Functions (like this one), however it for example works only with v2 runtime and is not supported with v3 and so on. Also, I am not sure whether embedding the UI from within the Function is the most efficient thing to do - performance wise, since the Function will become quite large due to the included libraries.

Leave a Comment

Your email address will not be published. Required fields are marked *

Loading...