OpenAPI-Spezifikation

Die OpenAPI-Spezifikation (OAS) definiert eine standardmäßige, sprachunabhängige Schnittstelle zu RESTful-APIs, die es sowohl Menschen als auch Computern ermöglicht, die Schnittstellen ohne Zugriff auf Quellcode, Dokumentation oder durch Überprüfung des Netzwerkverkehrs zu erkennen und zu verstehen. Die verwendete Version der OpenAPI-Spezifikation ist OpenAPI 3.0.

Weitere Informationen zu OpenAPI 3.0 (Beschreibung und Vorgaben) sind in der offiziellen Dokumentation zu finden.

Anhand einer OpenAPI-Definition können Server und Clients in verschiedenen Programmiersprachen generiert und eine verständliche (fachliche) Schnittstellenbeschreibung erzeugt werden. Die folgenden Abschnitte beschreiben die Best Practices dafür, wie Nachbarsystemschnittstellen in eine OpenAPI-Spezifikation überführt werden und welche Werkzeuge dabei verwendet werden sollten.

1. Erstellung von OpenAPI-Spezifikationen

1.1. Mapping von fachlicher Schnittstellenbeschreibung auf OpenAPI-Spezifikation

Die Schnittstellenbeschreibung, die im Rahmen der Systemspezifikation erstellt wird, spezifiziert die angebotene(n) Nachbarsystemschnittstelle(n) (NST) aus fachlicher Sicht und gibt keine Auskunft über technische Details. Für das Erstellen dieser fachlichen Schnittstellenbeschreibung wird die Vorlage Schnittstellendokumenation verwendet. Die fachlichen Schnittstellenbeschreibungen nach den Vorgaben der IsyFact enthalten in erster Linie die verwendeten Entitäten sowie Eingabe und Ausgabe Parameter. Ergänzt werden diese durch weitere Spezifika (z.B. Kurzbeschreibung, Synchron/Asynchron, Online/Offline …). Diese Schnittstellenbeschreibung soll im Rahmen des Systementwurfs technisch als eine OpenAPI-Spezifikation konzipiert und bereitgestellt werden.

Bei der Erstellung der Spezifikation sind die Vorgaben und Konventionen für REST-Services zu beachten. Relevante Vorgaben beziehen sich u.a. auf den Aufbau der URls und der Anfrage, die Verwendung der HTTP-Verben und Statuscodes.

Die folgenden Abschnitte stellen ein Vorgehen zum Mappen der fachlichen Schnittstellenbeschreibung auf eine OpenAPI-Spezifikation vor. Alle Schnittstellen einer Anwendung sollen in einer einzigen OpenAPI-Spezifikation beschrieben werden.

Die Entitäten und die Datentypen in den fachlichen Schnittstellenbeschreibungen werden mithilfe der OpenAPI Schemaobjekte definiert. Schemaobjekte können Objekte, aber auch primitive Datentypen und Listen (Arrays) sein. Schemaobjekte unterstützen auch Polymorphismus. Dies ermöglicht auch Vererbung- und Kompositionsrelationen zwischen den Objekten. Diese Entitäten können so an beliebiger Stelle in der Spezifikation als Referenzobjekte genutzt werden.

Die Eingabe/Ausgabe Parameter in den fachlichen Schnittstellenbeschreibungen sind Entitäten oder Datentypen. Diese Parameter werden zuerst als Schemaobjekte definiert. Anschließend werden sie als Parameterobjekte oder als Request-Body-Objekte den Schnittstellen zugewiesen, je nachdem wie sie bei der Eingabe/Ausgabe benötigt werden.

IsyFact Schnittstellenbeschreibung OpenAPI 3 Spezifikation Beispiel und Bemerkungen

NST_Schnittstelle

path

NST_Mitarbeiter_suchen

paths:
  /mitarbeiter/sucheNachSuchkriterien:

Der Pfadname muss den Vorgaben und Konventionen für REST-Services entsprechen.

NSE_Entität (Input)

schema oder type

NSE_Mitarbeiter_Suchkriterien:

NSE_Mitarbeiter_Suchkriterien:
  type: "object"
  properties:
   bundeslandSchluessel:
     $ref: '#/components/schemas/Bundesland'
   ort:
     type: "string"
   trefferanzahl:
     type: "integer"
     format: "int64"

oder

parameters:
  - in: "query"
    name: "bundeslandSchluessel"
    schema:
      $ref: '#/components/schemas/Bundesland'
  - name: "ort"
    in: "query"
    schema:
      type: "string"
  - name: "trefferAnzahl"
    in: "query"
    schema:
      type: "integer"

Es wird empfohlen, die Attribute der Eingabe-Entitäten, die als Abfrageparameter (z.B. Suchkriterien) verwendet werden, als Query Parameters zu definieren. Es wird empfohlen, Entitäten mit komplexen oder vertraulichen Suchkriterien als Schemaobjekt zu spezifizieren, um das Erfassen dieser Informationen, z.B. durch Logger, zu vermeiden.

Die Eingabe-Entitäten, die im Body verarbeitet werden (z.B. Hinzufügen einer neuen Entität oder Bearbeiten einer vorhandenen Entität), werden als Schemaobjekt definiert.

NSE_Entität (Output)

responses mit schema

responses:
  '200':
    description: successful operation
    content:
      application/json:
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Mitarbeiter'
  '405':
    description: "Ungültige Suchkriterien"

Mit Schemaobjekt für NSE_Mitarbeiter:

Mitarbeiter:
  type: "object"
  properties:
    id:
      type: "integer"
      format: "int64"
    name:
      type: "string"
    vorname:
      type: "string"
    bundeslandSchluessel:
      $ref: '#/components/schemas/Bundesland'
    telefonnummer:
      type: "string"

NSA_Attribut

property

id:
  type: "integer"
  format: "int64"

DTY_Datentyp (einfach)

type

DTY_Ganzzahl:

type: "integer"

DTY_Datentyp (komplex)

schema

DTY_Bundesland

Bundesland:
  type: string
  enum:
    - BW
    - BY
    - BE
    - BB
    - HB
    - HH
    - HE
    - MV
    - NI
    - NW
    - RP
    - SL
    - SN
    - ST
    - SH
    - TH

Kurzbeschreibung

description

info:
  description: "Ein Beispiel für das Mapping einer fachlichen Schnittstelle"

Offline/Online

keine Entsprechung

Synchron/ Asynchron

keine Entsprechung

Schnittstellentyp

verb

get, post, put, delete

Das passende Verb, um die Art der Transaktion zu beschreiben (Lese-, Schreib- oder Löschvorgang). Vorgaben zur Wahl des Verbs finden sich in den Vorgaben zur Verwendung von HTTP-Methoden.

Die für die Mapping-Tabelle genutzte Beispiel-Schnittstellenbeschreibung und das Ergebnis als OpenAPI-Spezifikation ist im Beispiel NST_Mitarbeiter_suchen zusammenfassend dargestellt.

1.2. Übertragung von Metadaten

Metadaten werden als Header-Parameter übertragen. Zu Metadaten gehören u.a. Daten wie Benutzerkennung, Rolle, Tags, externe IDs. Nur die Metadaten, die nicht durch die IsyFact standardisiert werden, sind Teil der OpenAPI-Spezifikation.

Zur Spezifizierung von Header-Parametern wird der Eintrag in: header genutzt, wie das unten stehenden Beispiel zeigt.

Beispiel 1. Externe ID in NST_Mitarbeiter_suchen

Anforderung: Die Anwendung erwartet bei jedem Aufruf einer Schnittstelle eine Externe ID.

# …
paths:
  /mitarbeiter/sucheNachSuchkriterien:
    get:
      summary: "Suche Mitarbeiter nach Suchkriterien"
      description: "[...]"
      operationId: "sucheMitarbeiterNachSuchkriterien"
      parameters:
        - name: "externeId" (1)
          in: "header"
          schema:
            type: "integer"
            format: "int64"
 # …
1 Spezifikation des Header-Parameters

1.3. Übertragung fachlicher Informationen bei GET- und DELETE-Anfragen

Bei Anfragen zum Lesen (GET) oder Löschen (DELETE) werden gemäß den Vorgaben und Konventionen für REST-Services keine Informationen im Body übertragen. In einigen Fällen kann es jedoch vorkommen, dass der Server weitere Informationen benötigt, um die Anfrage erfolgreich bearbeiten zu können. Ein mögliches Szenario ist die Protokollierung der Zugriffshistorie inklusive Zugriffsgrund. Daher sollen in diesem Szenario die erforderlichen Informationen als URL-Parameter gesendet werden.

Zur Spezifizierung von URL-Parametern wird der Eintrag in: path genutzt, wie das unten stehenden Beispiel zeigt.

Beispiel 2. Protokollierung in NST_Mitarbeiter_suchen

Anforderung: Die Anwendung protokolliert bei jedem Aufruf einer Schnittstelle den Zugriffsgrund.

# …
paths:
  /mitarbeiter/sucheNachSuchkriterien:
    get:
      summary: "Suche Mitarbeiter nach Suchkriterien"
      description: "[...]"
      operationId: "sucheMitarbeiterNachSuchkriterien"
      parameters:
        - name: "zugriffsgrund" (1)
          in: "path"
          schema:
            type: "string"
 # …
1 Spezifikation des URL-Parameters

Falls die zu übermittelnden Informationen vertraulich sind, sollte ein Wechsel des HTTP-Verbs zu POST und die Übermittlung der Informationen im Body statt in der URL eruiert werden.

2. Beispiel NST_Mitarbeiter_suchen

Das Beispiel basiert auf der Spezifikationsmethodik für Nachbarsystemschnittstellen und wendet diese in einer vereinfachten Form an.

2.1. NST_Mitarbeiter_suchen

Kurzbeschreibung

Diese Schnittstelle bietet Nachbarsystemen die Möglichkeit, Mitarbeiter zu suchen und deren Daten abzufragen. Die Auswahl der Mitarbeiter erfolgt anhand einer Reihe von optionalen Suchkriterien.

Verwendete Entitätstypen (Input)

NSE_Mitarbeiter_Suchkriterien

Verwendete Entitätstypen (Output)

NSE_Mitarbeiterdaten

Aufgerufene Anwendungsfälle

AWF_Mitarbeiter_suchen

2.1.1. Eingabeparameter

Name

NSE_Mitarbeiter_Suchkriterien

Kurzbeschreibung

Die Kriterien zur Selektion von Mitarbeiter. Alle Attribute dieses Typs sind optional. Nicht befüllte Attribute werden daher nicht in die Suche einbezogen. Es dürfen beliebige Kombinationen von Attributen angegeben werden.

Name Datentyp

NSA_Bundesland_Schlüssel

DTY_Bundesland

NSA_Ort

DTY_Zeichenkette

NSA_Treffer_Anzahl

DTY_Ganzzahl

2.1.2. Ausgabeparameter

Name

NSE_Mitarbeiterdaten

Kurzbeschreibung

Dies ist die Rückgabeentität mit den Daten eines Mitarbeiters.

Name Datentyp

NSA_Name

DTY_Zeichenkette

NSA_Vorname

DTY_Zeichenkette

NSA_Bundesland_Schlüssel

DTY_Bundesland

NSA_Telefonnummer

DTY_Zeichenkette

2.2. Ergebnis (OpenAPI 3.0 Spezifikation)

OpenAPI: 3.0.0
info:
  description: "Ein Beispiel für das Mapping einer fachlichen Schnittstelle"
  version: "1.0.0"
  title: "Beispiel Anwendung"
paths:
  /mitarbeiter/sucheNachSuchkriterien:
    get:
      summary: "Suche Mitarbeiter nach Suchkriterien"
      description: "Diese Schnittstelle bietet Nachbarsystemen die Möglichkeit, Mitarbeiter zu suchen und deren Daten abzufragen. Die Auswahl der Mitarbeiter erfolgt anhand einer Reihe von optionalen Suchkriterien."
      operationId: "sucheMitarbeiterNachSuchkriterien"
      parameters:
        - in: "query"
          name: "bundeslandSchluessel"
          schema:
            $ref: '#/components/schemas/Bundesland'
        - name: "ort"
          in: "query"
          schema:
            type: "string"
        - name: "trefferAnzahl"
          in: "query"
          schema:
            type: "integer"
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Mitarbeiter'
        '405':
          description: "Ungültige Suchkriterien"
components:
  schemas:
    Mitarbeiter:
      type: "object"
      properties:
        id:
          type: "integer"
          format: "int64"
        name:
          type: "string"
        vorname:
          type: "string"
        bundeslandSchluessel:
          $ref: '#/components/schemas/Bundesland'
        telefonnummer:
          type: "string"
    Bundesland:
      type: string
      enum:
        - BW
        - BY
        - BE
        - BB
        - HB
        - HH
        - HE
        - MV
        - NI
        - NW
        - RP
        - SL
        - SN
        - ST
        - SH
        - TH

3. Generierung von Code durch OpenAPI-Spezifikationen

Es ist möglich, automatisch Code aus einer OpenAPI 3.0-Spezifikation zu generieren. Die IsyFact sieht hierzu den Einsatz des OpenAPI Generators vor.

4. Verwaltung von OpenAPI-Spezifikationen

Die OpenAPI-Spezifikation ist jeweils Bestandteil der spezifischen Projektdokumentation.

Damit die OpenAPI-Spezifikation verfügbar sein kann, muss diese auch verwaltet werden. In den jeweiligen Spring Projekten wird die OpenAPI-Spezifikation unter folgendem Pfad gespeichert: /src/main/resources/openapi.yml.

Falls es Änderungen innerhalb der OpenAPI-Spezifikation geben sollte, werden diese automatisch vom Versionskontrollsystem verwaltet.

5. Veröffentlichung von OpenAPI-Spezifikationen

Die OpenAPI-Spezifikationen werden mit jeder Veröffentlichung (Release) der Anwendung ausgeliefert. Für die Auslieferung und Veröffentlichung der OpenAPI-Spezifikation ergeben sich unterschiedliche Möglichkeiten, die in den folgenden Kapiteln beschrieben werden.

5.1. Artifactory

Die Auslieferung erfolgt als ein Teil vom zentral generierten Artefakt. Der Zugriff auf das Artefakt ist über das entsprechende Artifactory und/oder GitHub (für Open-Source gestellte Bausteine) möglich.

5.2. Antora

Antora erzeugt aus AsciiDoc-Quellen, die über mehrere Git-Repositories verteilt liegen können, eine gemeinsame, statische HTML-Seite.

Mithilfe des OpenAPI Generators kann aus der OpenAPI-Spezifikation AsciiDoc generiert werden. Die generierten AsciiDoc-Dateien können dann in Antora aufgenommen und gemeinsam mit der übrigen Dokumentation des Bausteins oder der Anwendung generiert und veröffentlicht werden.

Es empfehlt es sich auch, die OpenAPI-Spezifikation im YAML-Format in Antora zu verlinken.

Die Integration in Antora ermöglicht somit einen einfachen Zugriff auf verschiedene Versionen der OpenAPI-Spezifikation: einerseits das Herunterladen der OpenAPI-Spezifikationen für technische Nutzer (YAML-Format), andererseits den Zugang zu einer verständlichen Schnittstellen-Spezifikation für nicht technisch versierte Benutzer (AsciiDoc-Format).

Für die Generierung der Schnittstellenbeschreibung im AsciiDoc-Format ist der Generator asciidoc zu wählen. Die generierte HTML-Dokumentation kann auf einem Webserver oder auf GitHub/GitLab-Pages veröffentlicht werden und ist dann mit einem Webbrowser erreichbar. Hierzu müssen entsprechende Jobs in der Build-Pipeline angelegt werden.

5.3. Testumgebungen

Für den Betrieb in Testumgebungen ist es empfehlenswert, die OpenAPI-Spezifikation im YAML-Format über eine Schnittstelle bereitzustellen. Dazu wird ein eigener Endpunkt implementiert, der die im Ressourcen-Verzeichnis liegende OpenAPI-Spezifikation bereitstellt. Über einen Webbrowser kann so auf die aktuelle OpenAPI-Spezifikation der Anwendung im Betrieb zugegriffen werden, um z.B. Testwerkzeuge zu konfigurieren.