Entwurf von Microservices mit OpenAPI
Nach meiner Erfahrung gibt es kein Patentrezept, welches automatisch zu einem "guten" Entwurf von Microservices führt. Das konkrete Vorgehen hängt in erster Linie von den Gegebenheiten des jeweiligen Problems bzw. des Projektes ab, wobei insbesondere die Ausgangssituation entscheidend ist: Handelt es sich um die Erneuerung einer bestehenden Anwendung oder wird die Anwendung von Grund auf neu entwickelt?
Im Rahmen dieses Beitrages konzentriere ich mich auf den zweitgenannten Fall und orientiere mich dabei an der SEED(S) Methodik, welche von Ronnie Mitra und Irakli Nadareishviliim in Buch Microservices: Up and Running beschrieben wurde. Die beiden Autoren empfehlen sieben aufeinander aufbauende Entwicklungsschritte (siehe nächstes Kapitel). Schritt fünf beinhaltet eine formale Beschreibung der Abfrage und Aktion als Spezifikation (aka API first Design). Die in diesem Schritt empfohlene OpenAPI-Spezifikation (OAS) werde ich nachstehend anhand eines Beispiels genauer erläutern.
Sieben Entwicklungsschritte für den Entwurf von für Services (SEED(S))
Der SEED(S)-Prozess bietet eine praxiserprobte Methodik für den Entwurf von benutzerfreundlichen und robusten Service-Schnittstellen. Er besteht aus nachstehenden Schritten:
- Identifizierung der Akteure
- Identifizierung der Aufgaben, welche die Akteure zu erledigen haben
- Erkennen und Darstellung von Interaktionsmustern z.B. mit Sequenzdiagrammen
- Ableitung von Aktionen und Abfragen auf hoher Ebene auf der Grundlage der zu erledigenden Aufgaben und der Interaktionsmuster
- Beschreibung der einzelnen Abfragen und Aktionen als API-Spezifikation mit einem offenen Standard (wie z.B. OpenAPI)
- Einholen von Feedback zur API-Spezifikation
- Implementierung der Microservices auf der Basis der API-Spezifikation
Beschreibung von Abfrage und Aktion als Spezifikation (API first Design)
Bevor wir mit der Implementierung in Code für einen Microservice bzw. dessen API beginnen, sollte gemäss SEED(S) ein Schnittstellenvertrag entworfen werden. Hierbei empfiehlt sich die Verwendung von offenen Standards wie die OpenAPI-Spezifikation (OAS) oder GraphQL. Beide werden durch zahlreiche Werkzeuge unterstützt.
Ich beschränke mich im Folgenden auf die OpenAPI Spezifikation.
OpenAPI-Spezifikation (OAS)
Die OpenAPI-Spezifikation (OAS) definiert eine standardisierte, von der eingesetzten Programmiersprache unabhängige Notation für die Beschreibung von RESTful APIs. Ziel dabei ist es sowohl Menschen als auch Computern zu ermöglichen, die Funktionen eines Dienstes zu verstehen, ohne dass der Zugang zu Quellcode, zusätzlicher Dokumentation oder die Untersuchung des Netzwerkverkehrs erforderlich ist.
Bei korrekter Definition über OpenAPI kann ein Nutzer / eine Nutzerin in kurzer Zeit verstehen, wie er/sie mit einem Service interagieren kann (einschliesslich der Endpunkte, Parameter, Anfragemethoden und Antwortcodes). Ähnlich wie Schnittstellenbeschreibungen die Low-Level-Programmierung erleichtern, wird durch die OpenAPI-Spezifikation das Rätselraten über den korrekten Aufruf eines Dienstes verringert.
Komponenten der OpenAPI
Im Folgenden sind einige der wichtigsten Komponenten der OpenAPI-Spezifikation aufgeführt:
- Info: Allgemeine Informationen zur API wie Name, Version, Beschreibung, Kontaktinformationen des Betreibers und Lizenzinformationen.
- Paths: Definition der einzelnen Endpunkte oder Ressourcen der API, welche über HTTP-Anfragen aufgerufen werden. Für jeden Pfad müssen die unterstützten HTTP-Methoden (z. B. GET, POST, PUT, DELETE), Parameter, Anforderungen und mögliche Antworten angegeben werden.
- Parameters: Definition der Parameter, welche in den Pfaden oder Ressourcen der API verwendet werden. Beispielsweise können Query-Parameter, Header-Parameter oder Pfad-Parameter definiert werden.
- Request Bodies: Beschreibung der Daten, welche in einer HTTP-Anfrage an die API übermittelt werden.
- Responses: Beschreibung der möglichen Antworten, welche die API zurückgibt. Für jede Antwort muss der HTTP-Statuscode, eine Beschreibung und ein Beispiel angegeben werden.
- Security: Beschreibung, wie die API gesichert werden kann. Zum Beispiel kann die Verwendung von API-Schlüsseln, OAuth2 oder anderen Authentifizierungs- oder Autorisierungsmechanismen definiert werden.
Für weitere Informationen zu den genannten Komponenten verweise ich auf die offizielle OpenAPI-Spezifikation.
Anwendungsbeispiel
Im nachstehenden Beispiel enthält eine Product-Ressource, welche über die Pfade /products und /products/{productId} verfügbar gemacht wird. Die API unterstützt die HTTP-Methoden GET, POST, PUT und DELETE für die Verwaltung von Produkten. Weiter enthält das Beispiel unter der Komponente Schemas eine Definition für die Datenstruktur eines Produkts.
openapi: 3.0.2
info:
title: Product API
description: A simple API for managing products
version: 1.0.0
servers:
- url: http://localhost:8000
paths:
/products:
get:
summary: Get all products
operationId: getAllProducts
responses:
'200':
description: OK
post:
summary: Create a new product
operationId: createProduct
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
/products/{productId}:
get:
summary: Get a product by ID
operationId: getProductById
parameters:
- name: productId
in: path
required: true
description: The ID of the product to retrieve
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
put:
summary: Update a product by ID
operationId: updateProductById
parameters:
- name: productId
in: path
required: true
description: The ID of the product to update
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
delete:
summary: Delete a product by ID
operationId: deleteProductById
parameters:
- name: productId
in: path
required: true
description: The ID of the product to delete
schema:
type: string
responses:
'204':
description: No Content
components:
schemas:
Product:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
description:
type: string
price:
type: number
minimum: 0
Das Ergebnis obiger Definition kann mit Hilfe von verschiedenen Tools grafisch dargestellt werden (siehe Snapshot unten).
Ein oft verwendetes Werkzeug stellt das open source Tool Swagger Editor dar, welches eine OpenAPI-Spezifikation automatisch analysieren und daraus eine grafische Benutzeroberfläche generieren kann. Das Ergebnis ist eine interaktive Dokumentation, welche es Entwicklern ermöglicht, die API zu erkunden und ihre verschiedenen Endpunkte, Parameter und Antworten zu testen.
Bekannt ist auch Stoplight Studio, eine API-Designplattform. Sie ermöglicht es, OpenAPI-Spezifikationen grafisch zu entwerfen und zu bearbeiten. Weitere Tool sind Redocly, ReDoc und Apicurio.
Ein Beispiel: Wenn Sie eine Liste von Produkten abrufen möchten, wäre es üblich, die URL "/products" zu verwenden. Wenn Sie jedoch ein bestimmtes Produkt abrufen möchten, wäre die URL "/products/{productId}" (wobei "{productId}" durch die ID des Produkts ersetzt wird).
Diese Konvention erleichtert es auch anderen Entwicklern, Ihre API zu verstehen und zu verwenden, da sie sich an eine allgemein akzeptierte Praxis halten können.
Nutzen der OpenAPI-Spezifikation
- Standardisierung: OpenAPI stellt einen einheitlichen Standard für die Dokumentation von APIs bereit, welcher die Kommunikation zwischen API-Entwicklern, API-Nutzern und anderen Stakeholdern vereinfacht. Durch die Nutzung eines standardisierten Formats können auch Werkzeuge und Bibliotheken zur automatischen Generierung von Code und Dokumentationen effektiver eingesetzt werden.
- Verbesserte Dokumentation: Durch die Verwendung von OpenAPI kann die Dokumentation von APIs automatisch generiert werden. Das spart Zeit und stellt sicher, dass die Dokumentation immer auf dem neuesten Stand ist.
- Einfache Integration: Durch die Verwendung von OpenAPI können APIs einfacher in Anwendungen integriert werden. Entwickler können schnell und einfach auf die API-Dokumentation zugreifen und Anfragen an die API senden.
- Bessere Zusammenarbeit: OpenAPI erleichtert die Zusammenarbeit zwischen API-Entwicklern, API-Nutzern und anderen Stakeholdern. Die Spezifikation ist eine klare und konsistente Beschreibung der API, die von allen Beteiligten leicht verstanden werden kann.
- API-Testing: OpenAPI ermöglicht es Entwicklern, automatische Tests zu erstellen, um sicherzustellen, dass die API korrekt funktioniert und den Spezifikationen entspricht.
Zusammenfassung
Der API-Design First-Ansatz sieht vor, dass Sie Ihre API-Definition schreiben, bevor Sie mit der Implementierung des Codes beginnen. Dies ist insbesondere im Zusammenhang mit der Neuentwicklung einer Microservice basierten Architektur hilfreich.
- Ein effektives API-Design hilft allen Beteiligten, die Ressourcen sowie den Nutzen und das Zusammenspiel der verschiedenen Microservices durch ihre APIs schnell zu verstehen.
- Die Identifizierung von Designproblemen vor dem Schreiben von Code ist effizienter als die Suche nach Problemen nach der Implementierung.
- Sobald die API-Definitionen erstellt wurden, kann mit der Implementierung begonnen werden. Dank einem guten Design ist es einfacher, die Implementierungsaufgaben unter den Entwicklern aufzuteilen.