Skip to content

API-Client aus einem openapi.json File im Frontend ​

Installation der openapitools ​

Anders als im Backend gibt es für das Frontend kein Plugin, um den Openapi Generator zu integrieren, sondern muss als CLI Befehl ausgeführt werden. Mit diesem Befehl kann der openapi-generator typescript-axios global auf dem Rechner installiert werden:

shell
npm install @openapitools/openapi-generator-cli -g typescript-axios
Errorhandling

Möglicherweise erscheint bei dem Versuch die openapitools zu installieren, diese Fehlermeldung: error_install_openapi-generator.png

In diesem Fall können die folgenden Schritte ausgeführt werden (Quelle)

TIP

Es ist empfehlenswert, für die folgenden Befehle das Git Bash-Terminal zu nutzen.

  1. npm Konfigurieren

    shell
    npm config set prefix '~/.local/'

    Durch diesen Befehl wird die Zeile prefix=~/.local/ zur .npmrc-Datei hinzugefügt. Alternativ kann dies auch manuell erfolgen.

  2. Umgebungsvariablen prüfen

    ~/.local/ sollte in der PATH-Umgebungsvariable enthalten sein. Dies kann entweder manuell, oder über diesen Befehl erfolgen. ./bashrc sollte dabei durch das entsprechende Config-File des genutzten Terminals ersetzt werden.

    shell
    mkdir -p ~/.local
    echo 'export PATH="$HOME/.local/:$PATH"' >> ~/.bashrc
  3. Proxy konfigurieren

    Bei Bedarf muss zusätzlich noch mit folgendem Befehl der https-Proxy konfiguriert werden:

    shell
    export HTTPS_PROXY=<proxy url>

Nach Durchführung dieser Schritte kann der Installationsbefehl erneut ausgeführt werden.

Anschließend kann im Terminal mit dem Befehl openapi-generator-cli version geprüft werden, ob die Installation erfolgreich war.

Generierung des Codes ​

Es gibt zwei Möglichkeiten, den Befehl auszuführen, um den gewünschten Code generieren zu lassen.

1) Ausführen des Befehls im Terminal ​

Im Terminal kann, wenn man sich innerhalb der wls-gui-wahllokalsystem-Directory befindet, für jedes openapi.json-File mit folgendem Befehl der entsprechende Code generiert werden:

shell
openapi-generator-cli generate -i src/resources/openapis/<openapi-file> -g typescript-axios -o src/api/wls-clients/generated-<domain>-api --type-mappings=set=Array

NOTE

--type-mappings=set=Array sorgt dafür, dass an Stelle von Sets Arrays generiert werden.

Dabei gilt:

  • Das -i steht für Input und gibt den Ort an, an welchem das openapi.json-File gespeichert ist: "src/resources/openapis/<openapi-file>". <openapi-file> wird dabei durch das entsprechende Release-File ersetzt. Beispiel: openapi.broadcast.0.2.0.json
  • Das -o steht für Output und gibt den Ort an, an welchem der generierte Code gespeichert werden soll: "src/api/wls-clients/generated-<domain>-api". <domain> wird dabei durch den entsprechenden WLS-Service ersetzt. Beispiel: generated-broadcast-api
Beispiel Broadcast-API

Der komplette, zusammengesetzte Befehl für die Generierung der Broadcast API über das Terminal würde so aussehen:

shell
openapi-generator-cli generate -i src/resources/openapis/openapi.broadcast.0.2.0.json -g typescript-axios -o src/api/wls-clients/generated-broadcast-api --type-mappings=set=Array
Errorhandling

Möglicherweise ist die Generierung nicht erfolgreich, und diese Fehlermeldung tritt auf:

shell
Error: Error: Unable to access jarfile { path-to-project }\WLS 3.0\node_modules\@openapitools\openapi-generator-cli\versions\7.10.0.jar

    at { path-to-project }\WLS 3.0\node_modules\@openapitools\openapi-generator-cli\main.js:2:47463
    at ChildProcess.exithandler (node:child_process:427:5)
    at ChildProcess.emit (node:events:518:28)
    at maybeClose (node:internal/child_process:1104:16)
    at ChildProcess._handle.onexit (node:internal/child_process:304:5)

Node.js v22.11.0

Process finished with exit code 1

In diesem Fall muss zusätzlich noch mit folgendem Befehl der https-Proxy konfiguriert werden:

shell
export HTTPS_PROXY=<proxy url>

2) Ausführen des Skripts gen:<domain>-api ​

In der package.json kann der oben genannte Befehl als Skript hinzugefügt werden. Das sieht dann so aus:

json
 "scripts": {
    "dev": "vite",
    /* ... */
    "gen:<domain>-api": "openapi-generator-cli generate -i src/resources/openapis/<openapi-file> -g typescript-axios -o src/api/wls-clients/generated-<domain>-api --type-mappings=set=Array"
  },
Beispiel Broadcast-API

Der komplette Befehl für die Generierung der Broadcast API über das package.json-File würde so aussehen:

json
 "scripts": {
    "gen:<domain>-api": "openapi-generator-cli generate -i src/resources/openapis/openapi.broadcast.0.2.0.json -g typescript-axios -o src/api/wls-clients/generated-broadcast-api --type-mappings=set=Array"
  },
Errorhandling

Möglicherweise ist die Generierung nicht erfolgreich, und diese Fehlermeldung tritt auf:

shell
Error: Error: Unable to access jarfile { path-to-project }\WLS 3.0\node_modules\@openapitools\openapi-generator-cli\versions\7.10.0.jar

    at { path-to-project }\WLS 3.0\node_modules\@openapitools\openapi-generator-cli\main.js:2:47463
    at ChildProcess.exithandler (node:child_process:427:5)
    at ChildProcess.emit (node:events:518:28)
    at maybeClose (node:internal/child_process:1104:16)
    at ChildProcess._handle.onexit (node:internal/child_process:304:5)

Node.js v22.11.0

Process finished with exit code 1

In diesem Fall muss zusätzlich noch der https-Proxy konfiguriert werden. In der IDE kann dieser über die Environment-Variable in der Run-Config gesetzt werden.

RunConfig in IDE bearbeiten

Nutzung des generierten Codes ​

Es werden bei der Generierung unter anderem folgende Dateien erstellt:

  • base.ts: enthält die BaseApi Klasse als Grundlage für alle anderen Api Klassen
  • configuration.ts: enthält die Konfigurationsoptionen für den Client --> bietet die Möglichkeit den BASE_PATH aus dem base.ts-File zu überschreiben
  • common.ts: enthält allgemeine Hilfsfunktionen und Typdefinitionen
  • api.ts: enthält die spezifischen Datenmodelle, sowie die Api-Klasse mit den entsprechenden Methoden des Clients

Am Beispiel vom Broadcast-Service wird gezeigt, wie der Code anschließend aufgerufen werden kann:

Damit die korrekte URL hinterlegt wird, muss beim Erstellen jeder *ControllerApi-Instanz der basePath überschrieben werden:

typescript
import { BroadcastControllerApi, Configuration } from "@/api/wls-clients/generated-broadcast-api";
import { BROADCAST_SERVICE_API_URL } from "@/constants";

export function broadcastService() {
  const broadcastCA = new BroadcastControllerApi(
    new Configuration({ basePath: BROADCAST_SERVICE_API_URL })
  );
}
typescript
const WLS_SERVICE_API_URL = "/api/";

export const BROADCAST_SERVICE_API_URL = WLS_SERVICE_API_URL + "broadcast-service";

Die Api-Aufrufe erfolgen dann zum Beispiel so:

typescript
// broadcastService.ts
import { BroadcastControllerApi, Configuration } from "@/api/wls-clients/generated-broadcast-api";
import { BROADCAST_SERVICE_API_URL } from "@/constants";

export function useBroadcastService() {
  const broadcastCA = new BroadcastControllerApi(/* ... */);

  async function getMessage(wahlbezirkID: string) { 
    try { 
      const response = await broadcastCA.getMessage(wahlbezirkID);
      if (response.status == 204) {
        return { message: "", error: "Es konnten keine Daten gefunden werden" };
      }
      const messageDTO = response.data;
      const nachrichtID = messageDTO.oid;
      try {
        await broadcastCA.deleteMessage(nachrichtID);
      } catch {
        return {
          message: "",
          error: "Es ist ein Fehler beim Lesen der Nachricht aufgetreten",
        };
      }
      return { message: messageDTO.nachricht, error: "" };
    } catch (e) {
      return { message: "", error: (e as Error).message };
    }
  }
  return { getMessage };
}

Im Fall eines 400er Codes in der Response, was in den meisten Fällen einer WlsException entspricht, können diese Werte dann wie folgt aufgerufen und weiterverarbeitet werden:

typescript
// broadcastService.ts
import type { BroadcastMessageDTO } from "@/api/wls-clients/generated-broadcast-api";

import axios from "axios";

import {
  BroadcastControllerApi,
  Configuration,
} from "@/api/wls-clients/generated-broadcast-api";
import { WLSError } from "@/api/WLSError";
import { BROADCAST_SERVICE_API_URL } from "@/constants";

export function useBroadcastService() {
  const broadcastCA = new BroadcastControllerApi(/* ... */);

  async function postMessage(nachricht: string, wahlbezirkIDs: string[]) { 
    const broadcastMessageDTO = { wahlbezirkIDs, nachricht } as BroadcastMessageDTO;

    try { 
      await broadcastCA.broadcast(broadcastMessageDTO);
      return { error: "" };
    } catch (e) {
      if (axios.isAxiosError(e)) {
        if (e.response) {
          const error: WLSError = e.response.data;
          const errorMessage = error.service + " - " + error.message + " (Code: " + error.code + ")";
          return { error: errorMessage };
        } else {
          return { error: "Fehler beim Senden der Broadcast Nachricht" };
        }
      } else {
        return { error: "Fehler beim Senden der Broadcast Nachricht" };
      }
    }
  }
  return { getMessage, postMessage };
}

Die Ausgabe des Errors könnte zum Beispiel folgende sein: WLS-BROADCAST - Das Object BroadcastMessage ist nicht vollständig. (Code: 150)