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.

Anoop K.Sharma

I have followed your code and try to integrate it with my azure function v3. The xml document gets generated but generator.GenerateDocuments returns nothing with 0 count. Could you please suggest.

Oscar Bautista

Thanks for the post. How do I set up the c# comments so that the response is an array? Is it possible? In your example the api returns a single object. Is it possible the response is a collection or array of objects?

Oscar Bautista

Thanks for the quick response. What if it’s a custom list/collection? For example, this:

where T is AddressDto[]

Produced: “responses”: { “200”: { “description”: “AddressDto[]”, “content”: { “application/json”: { “schema”: { “$ref”: “#/components/schemas/HPHC.Phoenix.Host.Model.Search.SearchResultDto_HPHC.Phoenix.Host.Model.Address.AddressDto_” } } } }

So it looks like it is missing this in the generated swagger: “type”: “array”

Phil

Do you think OpenAPI.NET.CSharpAnnotations is abandoned by MS in favour of azfunc-openapi? It is still at preview status and hasn’t been updated in 16 months. The author of azfunc-openai works for Microsoft and it seems to be actively maintained. Would like to know your thoughts.

Jan Hajek

As far as I know, Microsoft is using OpenAPI.NET.CSharpAnnotations tool internally, so don’t think it is abandoned, yet. I have been closely tracking the work on https://github.com/aliencube/AzureFunctions.Extensions/ and I am really impressed with the progress there. Really hoping Microsoft puts more effort into this.

Jan Hajek

@Oscar: I will try to check on it and report back.

Also apologies, I might need to replace the comment system with Disqus or something, because the lack of threads and notifications is kind of bad.

jesus lopez

Baracuda OpenAPI Azure Functions NET Core 3.1 Generate the json file openAPI 3.0 and the front end view to interact with the API’s calls based on the setting defined in the json file openAPI 3.0.

https://www.nuget.org/packages/Barracuda.OpenApi/ https://www.chambapatodos.com/

mohit tyagi

The JSON produced is not acceptable in the swagger editor: https://editor.swagger.io/ How to generate the correct JSON?

Jan Hajek

I suggest looking at Microsoft’s take on OpenAPI for Azure Functions: https://github.com/Azure/azure-functions-openapi-extension which is maintained unlike this generator.

To submit comments, go to GitHub Discussions.