Skip to main content

API Guidance: Implementierungsanleitung für APIs

Application Programming Interfaces (APIs) sind ein wesentlicher Bestandteil moderner verteilter Systeme – und ein wesentliches Glied in der Datenlieferkette für moderne, datengesteuerte Organisationen. Sie sind daher unverzichtbar für das Ökosystem des Datenaustauschs, welches das Support Centre for Datasharing fördern möchte. In dieser dreiteiligen Serie, die von eLearning-Modulen begleitet wird, wollen wir konzentriertes und praktisches Wissen für diejenigen anbieten, die über die Entwicklung und den Einsatz einer API nachdenken und daher die Grundlagen dieser Technologie verstehen müssen, sowie für diejenigen, die mehr Informationen darüber suchen, was bei der Implementierung zu beachten ist.

Dieser Inhalt wird auf zwei Arten veröffentlicht:

  1. Hier als Website-Inhalt in drei Episoden, jeden Monat mit einer neuen Folge, und
  2. nach Abschluss der Serie als einzelnes Dokument, das Sie herunterladen und offline lesen können.

Der Leitfaden ist in Englisch, Französisch und Deutsch verfügbar. Auf jede Ausgabe folgen E-Learning-Module, die die jeweiligen Themen abdecken und Ihnen helfen, Ihr Wissen zu testen.

Die zweite Folge gab einen Überblick über die neuesten API-Typen. In der dritten Folge werden die Implementierungsrichtlinien für APIs erörtert und folgende Schwerpunkte gesetzt:

  • RESTful-Schnittstellen
  • GraphQL-Schnittstellen
  • Sicherheitsdesign
  • API-Dokumentation

Wir freuen uns auf Ihre Kommentare und laden Sie dazu ein, weiterführende Themen in unserem Forum zu besprechen.

 

  1. RESTful-Schnittstellen

RESTful-Schnittstellen sind nützlich, um Massendaten zu übertragen und wenn Ihre Service-Schnittstelle sowie die jeweiligen Anwendungsfälle behoben sind.

Wenn Sie mit dem Entwerfen einer API beginnen, sollten Sie die API nicht aus dem Code Ihrer Anwendung ableiten, z. B. Java-Klassen. Sehen Sie sich stattdessen den begrenzten Kontext der Domäne an und entwerfen Sie die API um die Kernentitäten der Domäne und die erforderlichen Funktionen. Insbesondere konzentriert sich eine REST-Schnittstelle auf Ressourcen. Ressourcen können Objekte, Tabellen, Dokumente und vieles mehr sein, z. B. die Entitäten Ihrer Kerndomäne. Kurzum: alle Daten, die Sie veröffentlichen möchten. Wenn Sie also eine REST-API entwerfen, sollten Sie eine hypermediale Denkweise anwenden, da die Verknüpfung verschiedener Ressourcen die Grundidee von RESTful-Schnittstellen ist. Beachten Sie auch, dass REST-Schnittstellen hauptsächlich für die Kommunikation zwischen Diensten und in sich geschlossenen Systemen verwendet werden, für den internen Gebrauch jedoch weniger häufig sind.

7.1 Grundlagen und Struktur

Wenn Sie eine REST-API entwerfen, müssen Sie sich um die vier Grundkonzepte kümmern: HTTP(S)-Protokoll für den Transport, URLs für die Adressierung von Ressourcen, das Datendarstellungsformat und die vordefinierten Methoden für HTTP.

RESTful-basierte Dienste sollten HTTPS/2 verwenden,1 da dies ein sichereres Transportprotokoll bietet.

In jedem Fall sollten die URLs auch das folgende Grundmuster einhalten, um Ressourcensätze, bestimmte Ressourcen und Aufrufmethoden für Ressourcen zu adressieren:

/{version}/{collection}/{resource id}/{method name}?{query parameters}

Sammlungen sollten im Plural benannt werden und Ressourcen müssen eine eindeutige Kennung haben. Kennungen sollten die Kamel-Fallnotation verwenden, z. B. “/v10/myFavoredCollection”.

Das im Hauptteil einer HTTP-Methode verwendete Datendarstellungsformat sollte JSON oder YAML sein. Die Struktur der Daten sollte in einer bekannten Schemadefinitionssprache angegeben werden, z. B. OpenAPIv3 (siehe Abschnitt 6 zur API-Dokumentation). Außerdem müssen die HTTP-Header „Content-Type“ und „Content-Language“ korrekt gesetzt sein. Der Benutzer einer API sollte in der Lage sein, das bevorzugte Format mithilfe des HTTP-Headers „Accept“ auszuwählen. Jede Ressource sollte eine Attribut "id“ enthalten, das die eindeutige Kennung der spezifischen Ressource darstellt. Ressourcen sollten ein strukturiertes Format haben, das die vollständigen Informationen der Ressource enthält.

Die GET-Methode wird verwendet, um bestimmte Ressourcen oder eine Liste von Ressourcen aus einer Sammlung anzufordern/ durchzusuchen. Suchparameter sollten definiert werden, um die Begrenzung der Anzahl der Ergebnisse und das Paging durch Auswertung der Abfrageparameter „Überspringen“ und „Begrenzen“ zu unterstützen. Die POST-Methode wird zum Erstellen neuer Ressourcen verwendet, während die PUT-Methode zum Aktualisieren/Ändern von Ressourcen verwendet wird. Die DELETE-Methode wird verwendet, um bestimmte Ressourcen zu entfernen.

Im Allgemeinen sollten alle Anfragen und Antworten HTTP-Headers unterstützen, um erforderliche oder nützliche Metainformationen zu übertragen, z. B. für die Suche nach „Results-Matching", „Results-Skipped“ und „Link".

7.2 Empfehlungen

Da sich APIs im Laufe der Zeit weiterentwickeln können, ist es wichtig, eine Versionierung der API-Versionen beizubehalten. Damit Benutzer einer API die Auswirkungen einer neuen Version abschätzen können, muss die API-Versionsnummer eindeutig sein, z. B. durch Übernahme der Regeln der Semantic Version Specification2 (SemVer). Eine API sollte die aktuelle Version und die vorherige Version für einen Zwischenzeitraum unterstützen. Die Versionsnummer sollte Teil jeder URL sein, z. B. https://api.expample.org/v1/...; alternativ könnte es gemäß dem Hypermedia-Paradigma mit HTTP-Headern implementiert werden, z. B. Accept: application/vnd.example ;version=1.0 .

Die Ergebnisse einer GET-Anforderung sollten ebenfalls zwischengespeichert werden können. Um dies zu erreichen, muss die Antwort die richtigen HTTP-Header für ETag, Last-Modified, If-None-Match und If-Not-Modified-Since enthalten. Wenn sich in einem Zeitrahmen zu viele Anforderungen befinden, sollte die Anforderung mit einer entsprechenden Fehlermeldung abgelehnt werden.

Im Allgemeinen sollte jede HTTP-Anfrage mit einem korrekten HTTP-Statuscode beantwortet werden. Vermeiden Sie die Verwendung Ihres eigenen Statuscodes und verwenden Sie stattdessen einen der vordefinierten HTTP-Statuscodes.

Neben den Geschäftsfunktionen sollte eine API Endpunkte für das interne Betriebsmanagement bereitstellen. Jede API sollte einen Status zur Überprüfung von Gesundheit, Lebendigkeit und Bereitschaft bereitstellen, z. B. unter den URLs “/healthz”, “/healthz/liveness” and “/healthz/readiness”. Live bedeutet, dass der Dienst grundsätzlich verfügbar ist, während Bereit bedeutet, dass der Dienst jetzt neue Anforderungen akzeptiert und alle von diesem Dienst verwendeten Dienste ebenfalls bereit sind.

Darüber hinaus wird empfohlen, dass der Dienst Metriken für die interne Überwachung bereitstellt, z. B. unter der URL „/Metriken“. Zu diesem Zweck könnten die Metriken das Textausstellungsformat von Prometheus verwenden, um Indikatorwerte anzufordern. Zu den Indikatoren sollten Elemente wie Verwendung, Fehler und Leistung gehören. Zum Debuggen von Diensten sollte den Headern eine eindeutige Ablaufverfolgungs-ID hinzugefügt werden, z. B. „Ablaufverfolgung". Die Ablaufverfolgungs-ID sollte eindeutig sein, an andere angerufene Dienste weitergeleitet, sofort zu jedem Anruf hinzugefügt (falls nicht vorhanden) und in den Protokollnachrichten enthalten sein.

7.3 Nützliche Links

​​​​​​​eLearning-Modul für Kapital 7

 

8. GraphQL-Schnittstellen

GraphQL-Schnittstellen sind nützlich, wenn Sie Daten flexibler bereitstellen möchten. Dies ist besonders nützlich, wenn nicht alle Anwendungsfälle im Voraus bekannt sind oder wenn sie sich häufig ändern. Ein Beispiel wäre eine Benutzeroberfläche, die von einer API bereitgestellt wird und für die sich die erforderlichen Daten häufig ändern. Mit GraphQL können Sie bestimmte Ansichten der Daten in Ihrem Backend bereitstellen, basierend auf einem komplexen Datenmodell, für das nur ein Einstiegspunkt erforderlich ist.

Abhängig von Ihrem Anwendungsfall kann eine GraphQL-Schnittstelle auch zusammen mit einer RESTful-Schnittstelle bereitgestellt werden.

8.1 Grundlagen und Struktur

Wenn Sie eine GraphQL-API entwerfen, müssen Sie sich um die vier Grundkonzepte kümmern – genau wie bei RESTful-Schnittstellen: HTTP (S) -Protokoll für den Transport, URLs für die GraphQL-Einstiegspunkte, die Datenmodelle und die vordefinierten Methoden für HTTP.

GraphQL-basierte Dienste sollten aus Sicherheitsgründen HTTPS/2 als Transportprotokoll verwenden.

Die GraphQL-Einstiegspunkt-URL sollte folgendermaßen aussehen:

              /{version}/gql/{user role}

Wie oben erwähnt, kann eine einzelne GraphQL-API im Prinzip einen einheitlichen Zugriff auf eine gesamte Datenbank ermöglichen – vorausgesetzt, ein geeignetes Datenmodell und Abfragespezifikationen wurden implementiert. In der Praxis wird jedoch empfohlen, mehrere Einstiegspunkte zu verwenden, idealerweise einen pro Benutzerrolle. Ironischerweise liegt der Grund für diese Empfehlung genau darin, dass GraphQL-APIs in der Lage wären, viele verschiedene Benutzer mit vielen verschiedenen Datenanforderungen zu bedienen. Dies mag zunächst seltsam erscheinen, da die vermeintlichen Vorteile von GraphQL-APIs in ihrer technischen Leistungsfähigkeit und Flexibilität liegen. Dieselben Funktionen stellen jedoch Sicherheitsherausforderungen dar, wenn ein generischer Einstiegspunkt von vielen verschiedenen Benutzern mit unterschiedlichen Rollen verwendet wird und Daten unkontrolliert aus der vollständigen Datenbank anfordert.

Als bewährte Methode sollten APIs gemäß einer einzigen, eindeutigen Sicherheitsrichtlinie implementiert werden. Der beste Weg, dies zu regulieren, besteht darin, im Fall einer GraphQL-API, verschiedene rollenbasierte Einstiegspunkte für verschiedene Benutzer anzubieten. Diese Einstiegspunkte sollten von einem „Policy Enforcement Point“ aus konsistent implementiert werden, d. h. sie sollten die Eingabedaten syntaktisch (anhand eines Schemas) validieren und die Authentifizierung und Autorisierung des Benutzers für jede Anforderung überprüfen. Insbesondere die Autorisierung sollte auf der „rollenbasierten Zugriffskontrolle“ (RBAC) basieren. Wenn sich jede Rolle auf ein bestimmtes Datenmodell bezieht, sollte sofort klar sein, welche Art von Informationen ein Benutzer mit einer bestimmten Rolle anzeigen oder ändern kann.

Das Datenmodell für jeden Einstiegspunkt sollte für die zugehörige Benutzerrolle umfassend und gut strukturiert sein. Die Datenmodelle sollten mindestens mit der Schema Definition Language (SDL) von GraphQL angegeben werden. Im Idealfall verwenden die Datenmodelle OpenAPIv3 (siehe Abschnitt API-Dokumentation) und konvertieren die erforderliche SDL-Datei aus der OpenAPIv3-Spezifikationsdatei.3.4

Um Daten zu exportieren, auszutauschen und abzufragen, muss die GraphQL-API die Abfrageoperation bereitstellen. Die „Mutations"-Operation sollte in diesem Zusammenhang nicht bereitgestellt werden. Die API kann die „Abonnement"-Operation bereitstellen, um abonnierte Benutzer zu informieren, wenn Daten aktualisiert werden.

8.2 Empfehlungen

Insbesondere für externe APIs, die Daten mit Dritten austauschen, sollte eine integrierte Entwicklungsumgebung (IDE) wie GraphiQL als Teil der API verfügbar sein. Auf diese Weise können Benutzer den Datenraum erkunden und GraphQL-Ausdrücke testen. Dies sollte auch dazu beitragen, die Entwicklung neuer Szenarien oder die Einbindung neuer Partner zu beschleunigen.

Da sich eine API im Laufe der Zeit leicht weiterentwickeln kann, ist eine Versionierung der API-Versionen wichtig. Damit die Benutzer einer API die Auswirkungen einer neuen Version abschätzen können, muss die API-Versionsnummer eindeutig sein und den Regeln der Semantic Version Specification 5(SemVer) entsprechen. Eine API sollte die aktuelle Version und die vorherige Version für einen Zwischenzeitraum unterstützen. Die Versionsnummer sollte Teil jeder URL sein, z. B. https://api.expample.org/v1//gql/...; alternativ könnte es gemäß dem Hypermedia-Paradigma mit HTTP-Headern implementiert werden, z. B. Accept: application/vnd.example ;version=1.0 . Da GraphQL selbst sehr flexibel auf Änderungen reagiert, insbesondere in Bezug auf Erweiterungen des Datenmodells, müssen nur Hauptversionen angegeben werden.

Die Ergebnisse einer GraphQL-Anforderung sollten zwischengespeichert werden können. Daher muss die Kennung der Ressourcen im Datenmodell eindeutig sein

{ „starship":{ „id":"3003", „name":"Imperial shuttle“ } }

Der GraphQL API-Einstiegspunkt sollte auch eine Überprüfung von Zustand, Liveness und Bereitschaft unterstützen, z. B. unter den URLs „/ healthz", „/ healthz/liveness“ und „/ healtz/readiness". Live bedeutet, dass der Dienst grundsätzlich verfügbar ist, während Bereit bedeutet, dass der Dienst jetzt neue Anforderungen akzeptiert und alle von diesem Dienst verwendeten Dienste ebenfalls bereit sind. Die GraphQL-Schnittstelle sollte ebenfalls eine Verwendung bieten. Für Debugging-Zwecke sollte die Verwendung und Weiterleitung einer Tracing-ID implementiert werden.

8.3 Nützliche Links

GraphQL – A query language for your API, https://graphql.org

GraphQL or Bust, https://nordicapis.com/api-ebooks/graphql-or-bust/

GraphiQL – GraphQL IDE Monorepo, https://github.com/graphql/graphiql

GraphQL Playground, https://github.com/prisma/graphql-playground

 

9. Sicherheitsdesign

Sicherheitsüberlegungen sollten von Anfang an eine wesentliche Rolle im API-Design spielen. Im Allgemeinen sollte eine Implementierung von Natur aus immer sicher sein, um unbeabsichtigtes Verhalten oder Angriffe durch Fehler zu vermeiden. Die Implementierung sollte eine gültige Verwendung der Schnittstelle sicherstellen, z. B. durch Implementierung einer starken Eingabevalidierung. Darüber hinaus sollte die Implementierung häufige Fehler wie Pufferüberläufe vermeiden. Um Probleme und Sicherheitsprobleme zu analysieren, sollten alle relevanten Ereignisse und Fehler jederzeit detailliert in einem Überwachungsprotokoll protokolliert werden.

9.1 Kommunikation

Wir empfehlen dringend, den gesamten Datenverkehr aus Datenschutz- und Sicherheitsgründen zu sichern. Zu diesem Zweck sollte die Sicherheit der Transportschicht sowohl für die externe als auch für die interne Kommunikation verwendet werden. Daher sollte HTTP(S)/2 auf der Transportschicht verwendet werden. Der Zugriff auf einen Dienst mit HTTP oder alten Verschlüsselungsprotokollen wie TLS 1.2 und früheren Versionen sollte abgelehnt werden. Sicherheitsmaßnahmen wie die Implementierung des HTTP Strict Transport Security Protocol (HSTS) und Perfect Forward Secrecy (PFS) sollten unterstützt werden.

Wenn in einem bestimmten Zeitraum zu viele Anrufe eingehen, sollte der Dienst die Anforderung vorübergehend ablehnen und dies durch Rückgabe eines Statuscodes signalisieren, z. B. „429 Zu viele Anforderungen“. Um solche Probleme zu vermeiden, könnte der Dienst in Betracht ziehen, die Anforderungsrate durch Signalisierungsratenlimits zu begrenzen, z. B. durch Verwendung der Header X-Rate-Limit-Limit, X-Rate-Limit-Remaining und X-Rate-Limit-Reset in einer Antwort.

9.2 Authentisierung und Autorisation

Mit Ausnahme von Daten, die als Open Data veröffentlicht wurden, sollte jeder Benutzer authentifiziert sein, um auf einen Dienst zugreifen zu können. Bekannte Benutzer sollten sich auch authentifizieren können. Die Authentifizierung sollte mithilfe gängiger Mechanismen wie OAuth2 oder OpenID implementiert werden. Wenn ein Dienst mit einem anderen Dienst kommuniziert, sollte sich der Dienst auch selbst authentifizieren, z. B. mithilfe eines regelmäßig erneuerten API-Tokens, das auf einem geheimen Verwaltungssystem wie Vault basiert.6

Die Berechtigung zum Zugriff auf eine Funktion eines Dienstes sollte auf einem Sicherheitskonzept der rollenbasierten Zugriffskontrolle (RBAC) basieren. Für jede Rolle sollte verständlich sein, welche Informationen die Benutzer einer bestimmten Gruppe anzeigen können und welche Rechte sie haben. Die Autorisierung sollte durch ein Inhaber-Token wie ein signiertes JSON-Web-Token7 (JWT) im HTTP-Header einer Anforderung implementiert werden. Die Ansprüche des Tokens sollten mindestens den Aussteller (iss), das Subjekt (sub), das Publikum (aud) und die Ablaufzeit (exp) umfassen.

 

Aus Anwendersicht ist eine qualitativ hochwertige Dokumentation ein wesentlicher Bestandteil jeder API. Um sicherzustellen, dass eine API von externen Parteien verwendet werden kann, muss ihre Dokumentation verständlich, korrekt, aktuell, umfassend und vollständig sein. Darüber hinaus sollte die Dokumentation öffentlich und kostenlos verfügbar sein. Nur eine gute Dokumentation zusammen mit einem guten Design und einer soliden Implementierung sorgen für eine erfolgreiche API.

Die API sollte „zuerst“ aus den Anwendungsfällen definiert werden, die aus dem domänengesteuerten Design und den Geschäftsprozessen abgeleitet wurden. Während der Implementierung der API sollten die Erfahrungen weiterentwickelt und genutzt werden, um die Spezifikation schrittweise zu verbessern.

10.1 Implementierungsgrundlagen

Die Dokumentation und der Schnittstellencode sollten aus der formalen Spezifikation der API generiert werden. Daher sollte die Spezifikation mithilfe des OpenAPIv3-Schemas und der SDL (Interface Definition Language) definiert werden8 Diese SDL sollte verwendet werden, um RESTful-APIs, GraphQL-APIs, Weblinks und Streams/Ereignisse anzugeben.

Die Spezifikation sollte Server, Sicherheitsmechanismen, Einstiegspunkte und alle Datenmodelle definieren.

Jeder Punkt der Spezifikation muss umfassend und präzise erklärt werden. Felder sollten so genau wie möglich definiert werden, z. B. das Attribut „format“ für alle Felder bereitstellen und benutzerdefinierte Zeichenfolgenwerte mithilfe regulärer Ausdrücke (regulärer Ausdruck) beschreiben:

              { "name": "color", "type": "string", "format": " ’red’ | ‘blue’ | ‘green’ " ” }

Die Beschreibungsfelder sollten verwendet werden, um den Zweck, die Funktionalität, die Verwendung und den Kontext der API selbst und aller ihrer Elemente zu beschreiben. Die Beschreibungsfelder sollten strukturierten oder formatierten Text enthalten, der die Markdown-Syntax verwendet.

Alle HTTP-Status, an die Codes zurückgegeben werden können, müssen ebenfalls aufgelistet und erläutert werden.

10.2 Empfehlungen

Jede Dokumentation sollte Anwendungsfälle, Domain-Storys,9 Sequenzdiagramme, Codebeispiele und andere Abbildungen enthalten, um die Verwendung und Funktionalität der API zu erläutern.

Da sich APIs im Laufe der Zeit weiterentwickeln, muss die Dokumentation einen Verlauf mit Änderungen für jede Version enthalten.

Die Dokumentation sollte online als Webseite, als druckbares E-Paper (pdf) frei verfügbar sein und von einem bekannten Ort aus verlinkt werden. Die Dokumentation sollte mithilfe einer CI/CD-Prozesskette automatisch generiert und aktualisiert werden.

Schließlich sollte die Dokumentation durch Testfälle in lesbarer und ausführbarer Form ergänzt werden, z. B. durch verhaltensgesteuerte Tests.10

 

Damit ist die API-Anleitungsserie abgeschlossen. Vergessen Sie nicht, die Materialien zu besprechen, indem Sie jede Folge kommentieren oder mit Ihren Kollegen in unserem Forum zu besprechen. Testen Sie Ihr Wissen auch in den eLearning-Modulen der SCDS API Guidance: https://elearningcourses.eudatasharing.eu/de/apiguidance/#/

API Guidance: Implementierungsanleitung für APIs
Image credit:
(C) 2020 Support Centre for Data Sharing