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:
npm install @openapitools/openapi-generator-cli -g typescript-axios
Errorhandling
Möglicherweise erscheint bei dem Versuch die openapitools zu installieren, diese Fehlermeldung:
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.
npm Konfigurieren
shellnpm config set prefix '~/.local/'
Durch diesen Befehl wird die Zeile
prefix=~/.local/
zur.npmrc
-Datei hinzugefügt. Alternativ kann dies auch manuell erfolgen.Umgebungsvariablen prüfen
~/.local/
sollte in derPATH
-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.shellmkdir -p ~/.local echo 'export PATH="$HOME/.local/:$PATH"' >> ~/.bashrc
Proxy konfigurieren
Bei Bedarf muss zusätzlich noch mit folgendem Befehl der https-Proxy konfiguriert werden:
shellexport 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:
openapi-generator-cli generate -i src/resources/openapis/<openapi-file> -g typescript-axios -o src/api/wls-clients/generated-<domain>-api
Dabei gilt:
- Das
-i
steht für Input und gibt den Ort an, an welchem dasopenapi.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:
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
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:
"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 "
},
Beispiel Broadcast-API
Der komplette Befehl für die Generierung der Broadcast API über das package.json
-File würde so aussehen:
"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 "
},
Errorhandling
Möglicherweise ist die Generierung nicht erfolgreich, und diese Fehlermeldung tritt auf:
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 bitte nach Möglichkeit 1 - Ausführen des Befehls im Terminal verfahren werden.
🚧 -> Die behebung dieses Problems wird in diesem Issue behandelt.
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 Klassenconfiguration.ts
: enthält die Konfigurationsoptionen für den Client --> bietet die Möglichkeit denBASE_PATH
aus dembase.ts
-File zu überschreibencommon.ts
: enthält allgemeine Hilfsfunktionen und Typdefinitionenapi.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:
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 })
);
}
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:
// 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 400
er Codes in der Response, was in den meisten Fällen einer WlsException entspricht, können diese Werte dann wie folgt aufgerufen und weiterverarbeitet werden:
// 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)