OpenAPI mit Azure Functions

post-thumb

Microsoft hat mit dem ersten Majorrelease im November 2021 der Extension für OpenAPI-Definition in Azure Functions endlich eine eigene Lösung veröffentlicht. Vor mittlerweile zwei Jahren hatte ich eine Serie zur Erstellung von Web APIs mit Azure Functions hier bei uns auf dem OKBlog geschrieben. Für die Neulinge: Hier gehts nochmal zum ersten Teil der Serie .

In der damaligen Implementierung wurde .NET Core 3.1 als technische Basis und einem Drittanbieter-Package für die Erzeugung der OpenAPI-Spezifikation verwendet. Währenddessen wurde .NET 6 (LTS) und sogar .NET 7 released. Wenn du nochmal durchlesen möchtest, wie die OpenAPI-Spezifikation mit .NET Core 3.1 und Swashbuckle umgesetzt wurde, gehts hier entlang .

Bereits im damaligen Beitrag hatte ich erwähnt, dass Microsoft an einer eigenen Lösung zur Implementierung der OpenAPI-Spezifikation arbeitete. In diesem Beitrag möchte ich nochmal das Beispiel-GitHub-Repo verwenden, um aufzuzeigen, welche Anpassungen notwendig sind, um auf die von Microsoft bereitgestellte Lösung umzustellen.

Revisit Web APIs mit Azure Functions: Swagger UI (Teil 4)

Wie erwähnt, gab es seit der initialen Erstellung des Beispiel-Repos einige Neuerungen. Hieraus ergeben sich im Wesentlichen die folgenden:

  • Upgrade von .NET Core 3.1 auf .NET 6
  • Update/Upgrade der Nuget-Packages
  • Ausbau von Swashbuckle aus der Solution
  • Einbau der OpenAPI-Extension von Microsoft

Im Blogbeitrag werde ich insbesondere auf die Unterschiede zu Swashbuckle und die notwendigen Anpassungen eingehen, um die OpenAPI-Spezifikation der APIs mit Microsofts Extension zu realisieren.

Projektanpassung

Um die die Microsoft Extension nutzen zu können, muss das Nuget dem Function-Projekt zunächst hinzugefügt werden:

<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.OpenApi" Version="1.x.x" />

Die entsprechenden Swashbuckle-Nuget-Verweise müssen natürlich entfernt werden. Dazu gehört auch die im Projekt befindliche Klasse SwaggerController.cs, welche primär für die Erzeugung der OpenAPI-Spezifikation als JSON und dem Rendern von Swagger diente.

In der Klasse Startup.cs sollte das Laden der Swashbuckle Dependency (AddSwashBuckle) ebenfalls entfernt werden. Für Microsofts Lösung wird kein explizites Laden der Dependency benötigt. Falls man allerdings die Swagger-Dokumentation anpassen möchte, wie z.B. den Titel, die Beschreibung, den Kontakt oder die Lizenzbestimmung, so kann dies über eine separate Klasse definiert werden.

Diese könnte zum Beispiel so aussehen:

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.OpenApi.Models;
using System;

namespace Application.Functions
{
    public class MyOkBlogOpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions
    {
        public override OpenApiInfo Info { get; set; } = new OpenApiInfo()
        {
            Version = GetOpenApiDocVersion(),
            Title = "OKBlog ToDo-Functions",
            Description = "Das ist eine Beschreibung für meine OKBlog ToDo-Function-App",
            TermsOfService = new Uri("https://blog.objektkultur.de"),
            Contact = new OpenApiContact()
            {
                Name = "Objektkultur",
                Email = "kontakt@objektkultur.de",
                Url = new Uri("https://objektkultur.de"),
            },
            License = new OpenApiLicense()
            {
                Name = "MIT",
                Url = new Uri("http://opensource.org/licenses/MIT"),
            }
        };

        public override OpenApiVersionType OpenApiVersion { get; set; } = GetOpenApiVersion();
    }
}

Dabei muss die Datei auch nicht separat in der Startup-Klasse eingebunden werden. Alles funktioniert automatisch.

OpenAPI-Spezifikation mit Microsofts Extension

Nachdem nun alle Swashbuckle-Verweise entfernt und mit Microsofts OpenAPI Extension ersetzt wurden, schauen wir uns einmal an, wie man nun die OpenAPI-Spezifikation für die Functions definiert.

Um einen besseren Überblick zu erhalten, schauen wir uns nun im folgenden die Attributierung der OpenAPI-Spezifikation für die Function StoreTodoItemCommandFunction an.

// omitted usings

[FunctionName("StoreTodoItemCommandFunction")]
[OpenApiOperation(operationId: "todo", tags: new[] { "todo" }, Summary = "StoreTodoItem", Description = "Save a new ToDo-Item", Visibility = OpenApiVisibilityType.Important)]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiRequestBody(contentType: "application/json", typeof(StoreTodoItemCommand))]
[OpenApiParameter(name: "x-my-custom-header", In = ParameterLocation.Header, Required = true, Type = typeof(string))]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(TodoItem), Description = nameof(HttpStatusCode.OK))]
[OpenApiResponseWithoutBody(statusCode: HttpStatusCode.NotFound, Description = nameof(HttpStatusCode.NotFound))]
[OpenApiResponseWithoutBody(statusCode: HttpStatusCode.Unauthorized, Description = nameof(HttpStatusCode.Unauthorized))]
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "Todo")] HttpRequest req,
    ILogger log)
{
  // omitted C# Code
}

Hierbei fallen insgesamt zwei Hauptunterschiede zur Umsetzung mit Swashbuckle auf (nächstes Listing). Zum einen ist das Namensschema bei Microsofts OpenAPI-Lösung einheitlich (OpenApi als Prefix für die Attribute), zum anderen müssen bei Swashbuckle die Angabe von Requestbodies innerhalb der Run-Parameter der Function-Methode eingefügt werden, was die Leserlichkeit stört und eine nachträgliche Pflege erschwert.

// omitted usings

[FunctionName("StoreTodoItemCommandFunction")]
[ApiExplorerSettings(GroupName = "todo")]
[ProducesResponseType(typeof(StoreTodoItemCommand), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "Todo")] HttpRequest req, 
    [RequestBodyType(typeof(StoreTodoItemCommand), "StoreTodoItemCommand Request-Body")],
    ILogger log)
{
  // omitted C# Code
}

Sicherlich ist der Vergleich nicht ganz fair, werden Attribute bei der Swashbuckle Implementierung erst gar nicht verwendet (z.B. ResponseBody etc.), doch kann man anhand des Beispiels schnell erkennen, dass die Attributierung mit Microsofts Lösung sowohl inhaltlich umfangreicher, als auch leichter zu pflegen ist. Aufgrund der einheitlichen Namensgebung kann der Entwickler direkt sehen, welche Attribute zur OpenAPI-Spezifikation gehören.

Swagger

Beim Ausführen der Function fällt sofort auf, dass insgesamt vier Swagger-APIs bereitgestellt werden:

Swagger-URL

Nach Aufruf der Swagger-UI erscheinen alle definierten APIs aufgelistet. Zusätzlich erhält man hier auch die Möglichkeit, alle Endpunkte zu autorisieren (via “Authorize”).

Swagger-UI-Startpage

Die APIs beinhalten sämtliche Informationen, welche vorher via Attributierung an den Functions dekoriert worden sind. Hierzu gehört z.B. der body, welcher an die API gesendet wird, oder die Beschreibung der API im Allgemeinen.

Swagger-UI-API

Fazit

Die Extension von Microsoft beweist, dass die Nutzung und Integration in bestehende Projekte sehr gut gelingt. Hierdurch können Abhängigkeiten zu Drittanbieter-Packages reduziert werden. In der Vergangenheit musste ich leider öfter feststellen, dass aufgrund von Swashbuckle-Abhängigkeiten zu anderen Paketen wie z.B. System.Text.Json bestand und wir somit nur mit bestimmten Versionen arbeiten konnten und einige Features dadurch verwehrt blieben.

Wenn man also auf .NET 6/7 upgraden möchte, kann man diesen Anlass auch dazu nutzen, Microsofts Extension zur OpenAPI-Definition zu verwenden. Diese bietet eine umfangreiche Anpassbarkeit der APIs und somit auch einen großen Mehrwert für die Konsumenten der APIs.

Um die Änderungen und Anpassungen nachvollziehen zu können, gelangst du hier direkt zum Repo und dem zugehörigen Commit .

Lernen Sie uns kennen

Das sind wir

Wir sind ein Software-Unternehmen mit Hauptsitz in Karlsruhe und auf die Umsetzung von Digitalstrategien durch vernetzte Cloud-Anwendungen spezialisiert. Wir sind Microsoft-Partner und erweitern Standard-Anwendungen bei Bedarf – egal ob Modernisierung, Integration, Implementierung von CRM- oder ERP-Systemen, Cloud Security oder Identity- und Access-Management: Wir unterstützen Sie!

Mehr über uns

Der Objektkultur-Newsletter

Mit unserem Newsletter informieren wir Sie stets über die neuesten Blogbeiträge,
Webcasts und weiteren spannenden Themen rund um die Digitalisierung.

Newsletter abonnieren