Die Art und Weise, wie Unternehmen Anwendungen entwickeln und betreiben, hat sich im Laufe der Zeit stark gewandelt. Insbesondere im Bereich der serverlosen Architekturen hat sich Azure Functions als leistungsstarkes Werkzeug etabliert. Azure Functions ermöglichen es, Geschäftslogik dynamisch und skalierbar auszuführen, ohne sich um die zugrunde liegende Infrastruktur kümmern zu müssen. Allerdings stellt sich immer häufiger die Frage: Wann werden Azure Functions wirklich benötigt und wann können sie durch eine direktere Architektur ersetzt werden?
Der Hauptzweck einer Azure Function sollte darin bestehen, komplexe Logik zu verarbeiten, d.h. Daten zu transformieren, zu validieren oder externe Systeme zu integrieren. In vielen klassischen Implementierungen werden Azure Functions jedoch nur zum Weiterleiten von Daten verwendet. Ein Beispiel dafür ist die Speicherung von Nachrichten in einer Azure Queue: Azure API Management ruft eine Azure Function auf, die wiederum die Nachricht in die Queue schreibt.

Dieser Ansatz hat jedoch einige Nachteile. Jede ausgeführte Azure Function verursacht Kosten, insbesondere bei hohem Durchsatz. Außerdem erhöht sich durch die zusätzliche Verarbeitungsebene die Latenz, da der Request erst eine Azure Function durchlaufen muss, bevor er an die Queue weitergeleitet wird. Zudem können Cold Starts auftreten, die insbesondere bei latenzkritischen Anwendungen problematisch sind.
Hier setzt der Functionless-Ansatz an. Anstatt eine Middleware-Funktion zu verwenden, kann das Azure API-Management direkt mit dem Azure Queue Storage kommunizieren. Dadurch werden unnötige Verarbeitungsschritte eliminiert, Kosten reduziert und die Performance optimiert.

Functionless API Management: Die direkte Integration mit Azure Queue Storage
Die Grundidee hinter einem Functionless-Ansatz ist es, API-Management-Dienste so zu konfigurieren, dass sie direkt mit Azure-Diensten interagieren. In diesem Fall bedeutet das, dass API-Management nicht mit einer Azure Function, sondern direkt mit Azure Queue Storage kommuniziert.
Ein entscheidendes Element dieser Architektur ist die Nutzung der REST API von Azure Queue Storage, die es ermöglicht, Nachrichten direkt per HTTP-Anfrage in eine Queue zu schreiben. Hierbei wird Shared Access Signature (SAS) verwendet, eine Azure-Technologie, die sicheren Zugriff auf Speicherressourcen erlaubt, indem temporäre Token mit eingeschränkten Berechtigungen generiert werden.
Hier gibt es ein Functionless-Tutorial auf YouTube:
Schritt 1: Generierung einer Shared Access Signature (SAS)
Um API-Management direkten Zugriff auf Azure Queue Storage zu ermöglichen, muss eine Shared Access Signature (SAS) erstellt werden. Dies geschieht über das Azure Portal in den Einstellungen des entsprechenden Queue Storage Accounts. Dort kann eine SAS generiert werden, die nur die benötigten Berechtigungen (z. B. Schreiben und Lesen) gewährt.
Sobald die SAS-URL verfügbar ist, kann sie für API-Aufrufe genutzt werden, um Nachrichten sicher in die Queue zu schreiben.

Schritt 2: Direkte API-Integration mit Postman testen
Um die direkte Kommunikation mit Azure Queue Storage zu testen, kann eine POST-Anfrage mit Postman durchgeführt werden. Wichtig zu beachten ist, dass Azure Queue Storage standardmäßig XML als Nachrichtenformat erwartet. Die Nachricht muss in einem bestimmten Format kodiert sein:

In der URL müssen noch die Query-Parameter aus dem SAS-Token angegeben werden.
Erfolgreiche Anfragen führen zu einer 201 Created
-Antwort, die bestätigt, dass die Nachricht in die Queue geschrieben wurde.
Schritt 3: JSON-zu-XML-Transformation mit API-Management
Da viele moderne Anwendungen JSON als Standardformat verwenden, muss API-Management die JSON-Daten in das von Azure Queue Storage erwartete XML-Format umwandeln. Dies kann durch die Inbound-Policies von API-Management realisiert werden.
Transformation des JSON-Bodies in XML
Eine Inbound-Policy liest den JSON-Request Body, wandelt ihn in Base64-kodiertes XML um und setzt den Content-Type
auf application/xml
. Dies geschieht über folgende Policy:
<inbound>
<base />
<set-variable name="requestBody" value="@((string)context.Request.Body.As<JObject>())" />
<set-body>@("<QueueMessage><MessageText>" + Convert.ToBase64String(Encoding.UTF8.GetBytes(context.Variables["requestBody"])) + "</MessageText></QueueMessage>")</set-body>
<set-header name="Content-Type" exists-action="override">
<value>application/xml</value>
</set-header>
</inbound>
Anpassen der API-URL für die Queue API
Zusätzlich muss die API-Management-Policy sicherstellen, dass die Anfrage an die richtige Queue-URL mit dem SAS-Token weitergeleitet wird:
<backend>
<base />
<set-backend-service base-url="https://<STORAGE_ACCOUNT>.queue.core.windows.net/<QUEUE_NAME>/messages?SAS_TOKEN" />
</backend>
Nach dieser Konfiguration kann die API direkt mit der Queue kommunizieren, ohne dass eine Azure Function erforderlich ist.
Herausforderungen des Functionless-Ansatzes
Obwohl der Functionless-Ansatz viele Vorteile bietet, gibt es auch einige Herausforderungen. Die Verwaltung der API-Management Policies erfordert eine präzise Konfiguration, da Fehler in der Transformation zu unerwarteten Ergebnissen führen können.
Außerdem ist die Testbarkeit von API-Management Policies schwieriger als bei klassischen Code-basierten Lösungen. Während Azure Functions durch Unit- und Integrationstests überprüft werden können, müssen API-Management Policies oft separat getestet werden.
Ein weiterer Aspekt ist die Limitierung der Azure Queue API. Da sie ausschließlich XML verarbeitet, kann es für komplexe Datenstrukturen notwendig sein, zusätzliche Anpassungen vorzunehmen oder alternative Speicherlösungen wie Cosmos DB oder Blob Storage in Betracht zu ziehen.
Fazit: Wann ist Functionless sinnvoll?
Der Functionless-Ansatz ist eine leistungsstarke Möglichkeit, Kosten zu senken, Latenzzeiten zu minimieren und unnötige Verarbeitungsschritte zu eliminieren. Besonders für einfache Anwendungsfälle, in denen Daten lediglich von einer API an eine Queue weitergeleitet werden, eignet sich dieser Ansatz hervorragend.
Allerdings sollten Unternehmen sorgfältig prüfen, ob API-Management allein ausreicht oder ob zusätzliche Verarbeitungsschritte erforderlich sind, die eine Azure Function rechtfertigen.
In vielen Fällen kann eine Kombination beider Ansätze sinnvoll sein: Azure Functions für komplexe Datenverarbeitung und API-Management für effiziente Weiterleitung von Daten.
Letztendlich zeigt der Functionless-Ansatz, dass intelligente API-Management-Richtlinien viele klassische Middleware-Komponenten ersetzen können und eine moderne, performante und kosteneffiziente Cloud-Architektur ermöglichen.