Strategie

API-Design

API-Design

Im ersten Teil dieser Post-Serie wurde eine Einführung in die API-Economy gegeben. Sie definiert sich über die Disziplinen API-Design, API-Development, API-Governance und API-Management. In diesem Artikel liegt der Fokus auf dem API-Design.

API-Design beschäftigt sich mit dem Entwurf der angebotenen Schnittstellen / APIs. Dazu gehören neben der Auswahl geeigneter Paradigmen (z.B. REST oder SOAP Interface) auch die Bestimmung der ausgetauschten Datenformate (z.B. JSON vs. XML) und marktüblicher Standards (z.B. Open Data).

Da im Rahmen des Designs die eigentlichen Application Programming Interfaces (API) als verbindlicher Vertrag mit dem Consumer entstehen, ist eine Dokumentation basierend auf akzeptierten Formaten (z.B. OpenAPI oder Swagger) notwendig.

API-Design hat Auswirkung auf die IT-Architektur, insbesondere wenn sie dem aktuellen Ansatz der Microservices folgt. Kleine, zustandslose Software-Komponenten oder Lambdas, welche horizontal skalierende Services ermöglichen, bedürfen zwingend einer schlanken, umgebungsagnostischen Infrastruktur.

Im Ergebnis gibt API-Design die Richtlinie für die Entwicklung der Provider und Consumer vor.

(Business) Domain Driven Design

Die API soll (automatisierten) Zugriff auf Geschäftsobjekte (Entitäten) und -prozesse (Operationen) bieten. Auch wenn sie durch eine technische Implementierung realisiert wird, steht beim Design die Orientierung am Geschäftsmodell des API-Anbieters (Provider) im Vordergrund. Technische Aspekte (Filterung, Sortierung) und Einschränkungen (Constraints) sind sekundär und finden sich eher im API-Development-Prozess wieder.

Beim Entwurf einer API (ähnlich zum objekt-orientieren Design) hat sich die Anwendung des Domain Driven Design bewährt. Objekte und Prozesse werden nach fachlichen Domänen gruppiert, wobei jede Domäne über Signale (Events) über Zustandsänderungen informiert. Die technische Abbildung über seinen Service-Bus o.ä. ist denkbar einfach.

Geschäftsobjekte

Bei der Modellierung einer API werden daher zunächst die Geschäftsobjekte (Entity) identifiziert und konsolidiert. Jede Entität erhält einen (domänenspezifischen) Namen sowie die Liste der allgemeinen Attribute. Im Rahmen der Normalisierung gilt es zwischen “all-umfassenden” Entitäten mit sämtlichen Attributen und schlanken Versionen mit Querverweisen abzuwägen. Ein Modell, welches alle Varianten über Attribute abbildet, ist zu vermeiden (s. Abb. 1). Ein “Core”-Modell, welche nur aus Referenzen besteht, ebenso.

Normalisierung des Modells

Normalisierung des Modells

Wichtig ist, dass in der API jede Entität über eine eindeutige ID adressierbar ist. Im Datenbank-Umfeld kommen hierfür automatisch vergebene Werte (SERIAL) oder ausreichend zufällige Werte (GUID) zum Einsatz. Im Umfeld web-basierter APIs setzt man stattdessen auf Uniform Resource Identifier (URI), vereinfacht gesagt auf URLs.

Geschäftsprozesse

Geschäftsprozesse beschreiben die Anlage und Verarbeitung und arbeiten mit oder auf Geschäftsobjekten. So ist das Neuanlegen eines Kunden eine Operation, welche in der Existenz einer neuen Instanz einer Entität (“Kunde”) resultiert. Gleiches gilt für das Lesen, Aktualisieren und Löschen von Kunden. Dieser Satz an Standard-Operationen wird in der Regel als CRUD (create, read, update, delete) abgekürzt. Sie finden sich in der Syntax von SQL (INSERT, SELECT, UPDATE, DELETE) genauso wie im REST-Paradigma. Im letzteren findet eine Abbildung über die HTTP-Verben (POST, GET, PUT, DELETE)

Jede der zu modellierenden Prozesse hat ein Ergebnis, abgebildet über einen Rückgabe-Wert. In den meisten Fällen wird dies das erzeugte oder geänderte Geschäftsobjekt sein. In anderen Fällen ist es nur der Identifier und in manchen Fällen (z.B. Löschen) nur ein Indikator, ob die Operation durchgeführt werden konnte oder nicht.

Relationen

Wo Beziehungen zwischen Entitäten abgebildet werden müssen, kann im Design auf zwei Verfahren zurückgegriffen werden:

  • Navigation über Assoziation, d.h. mindestens ein Modell muss die Verknüpfung zu einem anderen Modell unterstützen. Die Navigation (uni-/bi-direktional) von einer Entität zu ihrem Verbundpartner ist unmittelbar und damit sehr schnell.

  • Verknüpfung über Relation und Verwendung von Tupeln. Hier wird ein zusätzliches Modell entworfen, welches die Beziehung zweier Entitäten abbildet. Im eigentlichen Sinne ist das kein Geschäftsobjekt, aber es erlaubt die tatsächlichen Entitäten unverändert und frei von Ballast zu verknüpfen.

Dokumentation

Genaugenommen handelt es sich bei einem Application Programming Interface um eine Schnittstellenbeschreibung und damit um eine rudimentäre Form einer Dokumentation. Ihr Fokus liegt auf den technischen Aspekten der Schnittstelle, also Methoden- und Parameternamen, sowie Ergebnis- und Fehlertypen. Bereits mit diesen wenigen Informationen ist die technische Anbindung einer nutzenden Anwendung (Client) an den bereitstellenden Service möglich.

Den Bedürfnissen einer umfassenden Dokumentation wird sie allerdings nicht gerecht, so lässt sich die Semantik der beinhalteten Methoden und Parameter maximal durch entsprechende Benennung ausdrücken (z.B. CustomerId). Erklärende Worte oder Querverweise sind – weil technisch nicht notwendig - nicht vorgesehen.

Formate

WSDL

Die Web Services Description Language (WSDL) ist der Industrie-Standard im Umfeld von XML-basierten Webservices, wie SOAP. Sie beschreibt in einem (beliebig komplexen) XML-Dokument die zur Verfügung stehenden Operationen, sowie die Daten- und Antwort-Typen.

WSDL-Dokumente machen intensiven Gebrauch von XML-Schema zur Validierung der Inhalte und erlauben die Einbindung von weiteren Inhalten über sog. Namespaces. Diese Maßnahmen dienen der syntaktischen und semantischen Sicherheit, machen aber eine manuelle Erstellung oder Bearbeitung sehr schwierig und fehlerträchtig. Die WSDL ist daher auf die automatische Generierung (aus Modellen oder Software) bzw. die Verwendung von Design-Werkzeugen ausgelegt. Ihre über die formelle Beschreibung hinausgehenden Dokumentationsmöglichkeiten sind eher überschaubar.

WSDL ist über viele Jahre gereift und stellt wie bereits erwähnt den unangefochtenen Standard im Bereich definierter Remote Procedure Calls (RPC) dar. Es stellt die Brücke über verschiedene (objekt-orientierte) Programmiersprachen dar und steht damit in der Tradition von anderen Ansätzen wie CORBA. Aufgrund seines funktionsorientierten Ansatzes kommt es im Bereich ressourcenorientierter Methoden wie REST nur selten zum Einsatz.

Swagger / OpenAPI

Swagger ist der Shooting-Star unter den Werkzeugen zur API-Modellierung und Dokumentation. Swagger basiert auf einer einfachen, strukturierten Text-Datei (YAML oder JSON ), welche die Schnittstelle formal beschreibt (Methoden, Parameter, Rückgabewerte), sowie Meta-Informationen (Authentifizierung, Version, etc.) und Dokumentation beinhaltet. Eine automatisierte Prüfung (gegen ein Schema) unterstützt den Autor bei der Prüfung auf Vollständigkeit und Schlüssigkeit.

Diese Datei dient als Eingabewert für mehrere Tools, welche die Firma SmartBear Software ursprünglich entwickelt hat und welche nun als Open Source-Projekte weiterentwickelt werden:

  • Swagger Codegen ist eine Sammlung von Kommandozeilen-Werkzeugen welche aus der formalen API-Spezifikation entsprechende Source-Code Gerüste (“Stubs” bzw. “Skeletons”) für verschiedene Programmiersprachen ableiten. Entwickler können diese Code-Fragmente als Basis für die Entwicklung von Service Implementierungen oder Consumer Anwendungen nutzen.
  • Swagger UI verwendet ebenfalls die Textdatei als Eingangsdatum und generiert daraus eine interaktive Dokumentation auf HTML/JavaSkript-Basis, welche nicht nur eine Einsicht in die Dokumentation erlaubt, sondern auch das interaktive Testen erlaubt (s. Abbildung 2).
  • Swagger Editor schließlich ist ein Editor auf HTML-Basis, welcher das Erstellen der API-Spezifikation durch Syntax-Unterstützung und -Prüfung und interaktive Vorschau erleichtert. Swagger Editor kann unter https://editor.swagger.io/ als Service-Angebot genutzt oder lokal installiert werden.
Abbildung 2: Swagger UI Beispiel (Petstore)

Abbildung 2: Swagger UI Beispiel (Petstore)

SmartBear stellt die Swagger-Spezifikation und die oben genannten Werkzeuge kostenfrei unter einer Open Source-Lizenz zur Verfügung. Darüber hinaus hat es seine Erfahrung in die OpenAPI-Initiative eingebracht, welche – unter dem Dach der Linux-Foundation - die Standardisierung in Form der OpenAPI-Spezifikation (OAS) vorantreibt. Die Swagger-Spezifikation 3.x und die OAS 3.x sind faktisch identisch.

In Ergänzung zum Contract First-Ansatz über das Swagger Manifest ist auch ein umgekehrter Ansatz möglich, bei welchem die Swagger Spezifikation aus vorhandenem Programmcode generiert wird. Dazu werden die Quelltexte mit sog. Annotationen versehen, aus welchen durch einen Präprozessor die entsprechende Swagger Spezifikation erzeugt wird.

Weitere

Neben WSDL und Swagger bzw. OpenAPI gibt es noch weitere API-Spezifikationen, besonders zu nennen wären hier API-Blueprint und RAML zu nennen. Eine tiefergehende Beschreibung würde aber den Rahmen dieses Posts überschreiten.

Versionierung

Versionierung von APIs stellt sicher, dass mehrere Versionen einer Schnittstelle parallel in Betrieb sein können, ohne dass es zu Überschneidungen kommt. In Verbindung mit einem kontrollierten API-Lifecycle (Beschreibung wird sich im Post API-Management finden) gewährleistet Versionierung, dass Consumer Anwendungen eine dedizierte Version nutzen und gleichzeitig eine sanfte Migration auf eine neuere Version anstoßen können. Außerdem können Versionen vorzeitig ins Angebot aufgenommen und zum Test angeboten werden, auch wenn sie noch nicht die notwendige Reife erreicht haben (Beta-Version). Im Allgemeinen ist hierfür aber eine dedizierte Test-Umgebung (Sandbox) vorzuziehen.

Für die Versionierung von APIs gibt es mehrere Ansätze, deren Anwendbarkeit auch vom verwendeten Paradigma (SOAP, REST) abhängt. Dabei kommt in der Regel ein einstufiges oder dreistufiges Versionierungsschema zum Einsatz:

Build-Number

Im einstufigen Versionsschema gibt es nur einen Versionsindikator basierend auf einer ansteigenden Nummerierung. Mit jeder neuen Programmversion wird die sog. Build Number hochgezählt, auch wenn letztendlich nur qualitätsgesicherte Versionen veröffentlich werden.

Das einstufige Versionsschema lässt keinerlei Rückschlüsse auf den Funktionsumfang der API zu, man kann hier nur davon ausgehen, dass eine neuere Version sämtliche Funktionen bisheriger Versionen ergänzt und nicht ersetzt (oder verwirft). Entwickler von Consumer Anwendungen können so eine API-Mindestversion voraussetzen, die für die Nutzung durch ihre Anwendung notwendig ist.

Major, Minor und Patch-Level

Das dreistufige Versionsschema verwendet eine Gruppe von Zahlen (z.B. 1.8.92), denen eine unterschiedliche Bedeutung zukommt. Sie werden (von links nach rechts) als Major-, Minor- und Patch-Level bezeichnet.

  • API-Versionen mit gleicher Major-Nummer (1.x.x) bieten Consumer-Anwendungen eine stabile Schnittstelle, da sie mindestens den gleichen Funktionsumfang besitzen. Consumer Entwickler können davon ausgehen, dass ihre veröffentlichte Anwendung ohne Anpassung auch mit späteren API-Versionen gleicher Major-Nummer funktionieren werden.
  • API-Versionen mit gleicher Major- aber höherer Minor-Nummer können neue Funktionen hinzufügen oder bestehende Funktionen ergänzen. Dabei muss die Kompatibilität zu vorherigen Versionen gewahrt bleiben. Ein mögliches Szenario ist das Hinzufügen einer Operation, ohne dass eine existierende Operation dadurch ersetzt wird. Auch hier gilt für Consumer-Entwicklern, dass ihre Anwendung unverändert auch mit späteren Minor-Versionen funktionieren wird, allerdings nicht notwendigerweise mit früheren Versionen.
  • Das Patch-Level (manchmal wird auch hier die Build-Nummer verwendet) ist lediglich ein fortlaufender Zähler, der in der Regel auch nicht exponiert wird. Mithilfe der Patch-Level lässt sich der Entwicklungsfortschritt dokumentieren mit Fokus auf die Beseitigung von Fehlern und Stabilisierungsmaßnahmen. Eine funktionale Modifikation der Schnittstelle ist bei einer Änderung der Patch-Level nicht angezeigt.

Eine gesuchte Version muss auch transportiert werden können. Dazu gibt es – im Umfeld von Web-Services – verschiedene Ansätze, mit Vor- aber auch Nachteilen (s. Tabelle 1).

AnsatzBeispielBewertung
URL Pfad/api/2.0/customers/1Version wird über den URL Pfad adressiert. Erlaubt einfache Interpretation, Analyse und Tests. Gute Unterstützung durch gängige API-Management Software. Die Verwendung der Standard-Version durch fehlenden Versionsindikator bedarf besonderer Behandlung.
URL-Parameter/api/customers/1?v=2.0Version wird als URL Parameter transportiert. Einfache Interpretation, Analyse und Tests. Standard-Version kann durch fehlenden Versionsindikator erreicht werden. URL Parameter werden auch für andere Zwecke (Filter, Paginierung, etc.) im Service verwendet, die Verarbeitung der Versionsnummer muss vorab im Gateway stattfinden.
Standard HTTP-HeaderAccept: application/vnd.mymapp.2.0Versionstransport über HTTP Meta-Information unter Nutzung “üblicher” Header. Gute Unterstützung durch API-Management-Lösungen. Verwendung im Rahmen von Entwicklung und Test nur mit spezieller Software (z.B. SoapUI oder cURL) möglich, nicht mit einem Browser.
Eigener HTTP-HeaderMYAPP_VERSION: 2.0Versionstransport über HTTP Meta-Informationen über eigenen Header.Unterstützt durch einige API-Management-Lösungen. Verwendung im Rahmen von Entwicklung und Test nur mit spezieller Software (z.B. SoapUI oder cURL) möglich, nicht mit einem Browser. Mögliche Kollision mit Filterfunktionen von Sicherheitskomponenten (Firewall, Proxy, etc.).

Tabelle 1: Möglichkeiten der Versionswahl

Sicherheit

Natürlich müssen im Rahmen des API-Designs auch Fragen der Sicherheit auf vielen Ebenen definiert werden. Dazu zählen

  • Datensicherheit: Steuerung und Kontrolle des Zugriffs durch autorisierte Benutzer oder Systeme
  • Transportsicherheit: Sicherung des gesamten Übertragungsweges mit dem Ziel, unberechtigten Zugriff zu unterbinden
  • Integrität: Schutz der Daten vor unerwünschter Modifikation während des Transports oder im ruhenden Zustand

Der Bereich der Online-Kommunikation, besonders im Web-Umfeld, bietet Lösungen und technische Implementierungen für alle diese Fragen an. Authentifizierung und Autorisierung geschieht heutzutage über OAuth2 bzw. OpenID Connect. Transport Layer Security (TLS) sichert den Transport-Weg und durch den Einsatz entsprechender Zertifikate können Client und Server identifiziert werden. Und über Message Digest mit SHA256 oder HMAC können Manipulationen der transportierten Daten erkannt werden.

Tests

Ein Bewusstsein für API-Tests sollte spätestens in der Design-Phase geschaffen werden, da eine API möglichst einen stabilen und dauerhaften Vertrag abbilden sollte. Dies soll in dem späteren Betrieb, einen stabilen und fehlerfreien Funktionsrahmen schaffen. Folglich ist es erforderlich, neben dem positiven Funktionstest Szenarien und Möglichkeiten abzufangen, die außerhalb der definierten Spezifikation liegen und die Einhaltung des Schnittstellenvertrags forcieren.

Somit ergeben sich für Tests vier wesentliche Qualitätsfaktoren:

  1. Abbildung der fachlichen Funktionalität (die Abdeckung relevanter Anwendungsfälle)
  2. Prüfung und Einhaltung der technischen Rahmenbedingungen (Funktionalität, Stabilität, Ausnahmeszenarien)
  3. Verständlichkeit der Tests und der Ergebnisse auch für Nicht-Entwickler
  4. Reproduzierbarkeit und Wiederholbarkeit (Automatisierung)

Grundsätzlich kann mit der Entwicklung des API-Tests erst sinnvoll begonnen werden, sobald die Spezifikation weitgehend fertiggestellt ist. Ob die Testentwicklung während, nach oder bei der Entwicklung geschieht, obliegt der Arbeitsweise der Entwicklungskultur. Bei der Entwicklung der Tests sollte die Laufzeit der Tests deren regelmäßige Ausführung ermöglichen, um eine schnelle Reaktion auf das Scheitern eines Tests zu gewährleisten. Dabei wird je nach Abhängigkeit zu weiteren Systemen der Einsatz von sogenannten Mocks zur Abstraktion von nicht systemeigenem Verhalten empfohlen.

Ausblick

An dieser Stelle endet der Post zum Thema API-Design. Das Ziel ist es, einen verständlichen, konsistenten und erweiterbaren Vertrag zwischen dem Anbieter (Provider) und den Nutzern (Consumer) einer Schnittstelle zu beschreiben. Sobald diese Form der Spezifikation akzeptiert ist, können Provider und Consumer mit der Implementierung beginnen. Diesem Aspekt, dem API-Development, widmet sich der nächste Artikel dieser Serie.