generated from it-at-m/oss-repository-en-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #731 from it-at-m/716-generierung-der-service-schn…
…ittstellen-für-das-frontend 716 generierung der service schnittstellen für das frontend
- Loading branch information
Showing
30 changed files
with
1,802 additions
and
311 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
275 changes: 275 additions & 0 deletions
275
...hnik/guides/api-client-generation/generate-client-from-openapi-json-frontend.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
# 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 global auf dem Rechner | ||
installiert werden: | ||
|
||
```shell | ||
npm install @openapitools/openapi-generator-cli -g typescript-fetch | ||
``` | ||
|
||
::: details Errorhandling | ||
Sollte dabei diese Fehlermeldung auftauchen: | ||
![img_1.png](../../../public/error_install_openapi-generator.png) | ||
können die Schritte aus | ||
[diesem Stack-Beitrag](https://stackoverflow.com/questions/18088372/how-to-npm-install-global-not-as-root/59227497#59227497) | ||
befolgt werden. | ||
::: | ||
|
||
Bei Bedarf muss zusätzlich noch der Proxy konfiguriert werden. Anschließend kann im Terminal mit dem Befehl | ||
`openapi-generator-cli version` geprüft werden, ob die Installation erfolgreich war. | ||
|
||
## Individualisieren des Generators | ||
|
||
Damit der generierte Code zum Projekt passt, wurden die Templates des openapi-generators angepasst. | ||
|
||
> [!IMPORTANT] | ||
> Die Anpassung des Templates ist einmalig erfolgt und muss nicht für jeden Service wiederholt werden. Das geänderte | ||
> Template File wurde mit auf GitHub gepushed und liegt unter | ||
> [wls-gui-wahllokalsystem/src/api/wls-clients/custom-openapi-template-files](https://github.com/it-at-m/Wahllokalsystem/tree/dev/wls-gui-wahllokalsystem/src/api/wls-clients/custom-openapi-template-files). | ||
> Dieser Abschnitt dient nur zur Information und muss nicht für die Generierung des Codes ausgeführt werden. | ||
Mit dem Befehl | ||
|
||
```shell | ||
openapi-generator-cli author template -g typescript-fetch -o ./my-custom-template | ||
``` | ||
|
||
können die Template Files heruntergeladen werden. Hierbei steht `-o` für Output und es kann der Ort angegeben werden, an | ||
dem die heruntergeladenen Files gespeichert werden sollen. Für das WLS wurde das File `runtime.mustache` angepasst. Die | ||
veränderten oder hinzugefügten Codezeilen sind mit dem Kommentar `//Abweichung vom Standard-Template` gekennzeichnet. | ||
Folgende Code-Zeilen wurden hinzugefügt: | ||
|
||
::: code-group | ||
```:line-numbers=123 [runtime.mustache (Teil 1)] | ||
protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise<Response> { | ||
const { url, init } = await this.createFetchParams(context, initOverrides); | ||
const response = await this.fetchApi(url, init); | ||
// Abweichung vom Standard-Template: Zusätzliche Prüfung auf Statuscode 204 und >300 // [!code ++] | ||
if (response.status === 204) { // [!code ++] | ||
throw new WLSError(response, "Es konnten keine Daten gefunden werden", "T", response.status.toString()) // [!code ++] | ||
} else if (response && (response.status >= 200 && response.status < 300)) { // [!code ++] | ||
return response; // [!code ++] | ||
} else if (response && response.status == 400) { // [!code ++] | ||
const raw = await response.text(); // [!code ++] | ||
let content; // [!code ++] | ||
try { // [!code ++] | ||
content = JSON.parse(raw); // [!code ++] | ||
} catch (e) { // [!code ++] | ||
content = {}; // [!code ++] | ||
} // [!code ++] | ||
const content = JSON.parse(raw); // [!code ++] | ||
const wlsError = isWLSException(content) // [!code ++] | ||
? generateWlsExceptionFromJson(content) // [!code ++] | ||
: createDefaultWlsError({ // [!code ++] | ||
message: "Ungültige Anfrage", // [!code ++] | ||
code: response.status.toString(), // [!code ++] | ||
}); // [!code ++] | ||
throw new WLSError( // [!code ++] | ||
response, // [!code ++] | ||
wlsError.message, // [!code ++] | ||
wlsError.category, // [!code ++] | ||
wlsError.code, // [!code ++] | ||
wlsError.service // [!code ++] | ||
); // [!code ++] | ||
} | ||
throw new ResponseError(response, 'Response returned an error code'); | ||
} | ||
``` | ||
|
||
```:line-numbers=295 [runtime.mustache (Teil 2)] | ||
// Abweichung vom Standard-Template: Implementierung von WLSError und WLSException // [!code ++] | ||
export class WLSError extends Error { // [!code ++] | ||
override name: "WLSError" = "WLSError"; // [!code ++] | ||
category?: string; // [!code ++] | ||
code?: string; // [!code ++] | ||
service?: string; // [!code ++] | ||
constructor( // [!code ++] | ||
public response: Response, // [!code ++] | ||
msg?: string, // [!code ++] | ||
category?: string, // [!code ++] | ||
code?: string, // [!code ++] | ||
service?: string // [!code ++] | ||
) { // [!code ++] | ||
super(msg); // [!code ++] | ||
this.category = category; // [!code ++] | ||
this.code = code; // [!code ++] | ||
this.service = service; // [!code ++] | ||
} // [!code ++] | ||
} // [!code ++] | ||
// [!code ++] | ||
export function createDefaultWlsError({ // [!code ++] | ||
message = "Ein unbekannter Fehler ist aufgetreten", // [!code ++] | ||
category = "T", // [!code ++] | ||
code = "undefined", // [!code ++] | ||
service = "undefined", // [!code ++] | ||
}: { // [!code ++] | ||
message?: string; // [!code ++] | ||
category?: string; // [!code ++] | ||
code?: string; // [!code ++] | ||
service?: string; // [!code ++] | ||
}): WLSError { // [!code ++] | ||
return new WLSError( // [!code ++] | ||
new Response(), // [!code ++] | ||
message, // [!code ++] | ||
category, // [!code ++] | ||
code, // [!code ++] | ||
service // [!code ++] | ||
); // [!code ++] | ||
} // [!code ++] | ||
// [!code ++] | ||
export interface WLSException { // [!code ++] | ||
category: string; // [!code ++] | ||
code: string; // [!code ++] | ||
message: string; // [!code ++] | ||
service: string; // [!code ++] | ||
} // [!code ++] | ||
// [!code ++] | ||
/** // [!code ++] | ||
* Type guard to check if an object is a WLSException // [!code ++] | ||
* @param obj - The object to check // [!code ++] | ||
* @returns True if the object has all required WLSException properties with correct types // [!code ++] | ||
*/ // [!code ++] | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any // [!code ++] | ||
export function isWLSException(obj: any): obj is WLSException { // [!code ++] | ||
return ( // [!code ++] | ||
obj && // [!code ++] | ||
typeof obj.category === "string" && // [!code ++] | ||
typeof obj.code === "string" && // [!code ++] | ||
typeof obj.message === "string" && // [!code ++] | ||
typeof obj.service === "string" // [!code ++] | ||
); // [!code ++] | ||
} // [!code ++] | ||
// [!code ++] | ||
/** // [!code ++] | ||
* Generates a WLSError instance from a JSON object. // [!code ++] | ||
* @param content - The JSON-object with all relevant information // [!code ++] | ||
* @returns the generated WLSError object from JSON data // [!code ++] | ||
*/ // [!code ++] | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any // [!code ++] | ||
export function generateWlsExceptionFromJson(content: any): WLSException { // [!code ++] | ||
return { // [!code ++] | ||
category: content.category, // [!code ++] | ||
code: content.code, // [!code ++] | ||
message: content.message, // [!code ++] | ||
service: content.service, // [!code ++] | ||
}; // [!code ++] | ||
} // [!code ++] | ||
``` | ||
::: | ||
|
||
## 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-fetch -o src/api/wls-clients/generated-<domain>-api --template-dir src/api/wls-clients/custom-openapi-template-files | ||
``` | ||
|
||
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` | ||
- Das `--template-dir` sorgt dafür, dass die angepassten Templates bei der Generierung berücksichtigt werden und gibt | ||
den Ort an, an dem diese gespeichert sind: _"src/api/wls-clients/custom-openapi-template-files"_ | ||
|
||
::: details Beispiel Broadcast-API | ||
Der komplette 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-fetch -o src/api/wls-clients/generated-broadcast-api --template-dir src/api/wls-clients/custom-openapi-template-files | ||
``` | ||
::: | ||
|
||
#### 2) Ausführen des Skripts `gen:gen-<domain>` | ||
|
||
In der `package.json` kann der oben genannte Befehl als Skript hinzugefügt werden. Das sieht dann so aus: | ||
|
||
```json | ||
"scripts": { | ||
"dev": "vite", | ||
/* ... */ | ||
"gen:gen-<domain>": "openapi-generator-cli generate -i src/resources/openapis/<openapi-file> -g typescript-fetch -o src/api/wls-clients/generated-<domain>-api --template-dir src/api/wls-clients/custom-openapi-template-files" // [!code ++] | ||
}, | ||
``` | ||
|
||
::: details 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:gen-broadcast": "openapi-generator-cli generate -i src/resources/openapis/openapi.broadcast.0.2.0.json -g typescript-fetch -o src/api/wls-clients/generated-broadcast-api --template-dir src/api/wls-clients/custom-openapi-template-files" | ||
}, | ||
``` | ||
::: | ||
|
||
## Nutzung des generierten Codes | ||
|
||
Es werden bei der Generierung unter anderem `*ControllerApi.ts`-Files und `*DTO.ts`-Files erstellt. | ||
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: | ||
|
||
::: code-group | ||
```typescript [Vue File] | ||
import {BroadcastControllerApi, Configuration} from "@/api/wls-clients/generated-broadcast-api"; | ||
import {BROADCAST_SERVICE_API_URL} from "@/constants"; | ||
|
||
const broadcastCA = new BroadcastControllerApi( | ||
new Configuration({ | ||
basePath: BROADCAST_SERVICE_API_URL, | ||
}) | ||
); | ||
``` | ||
|
||
```typescript [constants.ts] | ||
const WLS_SERVICE_API_URL = "/api/"; | ||
|
||
export const BROADCAST_SERVICE_API_URL = WLS_SERVICE_API_URL + "broadcast-service"; | ||
``` | ||
::: | ||
|
||
Die Fetch Aufrufe erfolgen dann zum Beispiel so: | ||
|
||
```typescript | ||
import type {DeleteMessageRequest, GetMessageRequest} from "@/api/wls-clients/generated-broadcast-api"; | ||
import {WLSError} from "@/api/wls-clients/generated-broadcast-api"; | ||
|
||
const getParams: GetMessageRequest = {wahlbezirkID}; | ||
broadcastCA | ||
.getMessage(getParams) | ||
.then((content) => { | ||
const nachrichtID = content.oid; | ||
const deleteParams: DeleteMessageRequest = {nachrichtID}; | ||
broadcastCA.deleteMessage(deleteParams, postConfig()).catch(() => { | ||
errorToShow.value = "Es ist ein Fehler beim Lesen der Nachricht aufgetreten"; | ||
}); | ||
messageToShow.value = content.nachricht; | ||
}) | ||
.catch((error: WLSError) => { | ||
errorToShow.value = error.message; | ||
}); | ||
``` | ||
|
||
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: | ||
|
||
```typescript | ||
broadcastCA | ||
.then(/*xyz*/) | ||
.catch((error: WLSError) => { | ||
errorToShow.value = error.service + " - " + error.message + " (Code: " + error.code + ")"; | ||
}); | ||
``` | ||
|
||
Die Ausgabe wäre in diesem Beispiel: `WLS-BROADCAST - Das Object BroadcastMessage ist nicht vollständig. (Code: 150)` |
13 changes: 1 addition & 12 deletions
13
...ow-to-create-client-from-open-api-json.md → ...ow-to-create-client-from-open-api-json.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# API-Client Generierung | ||
|
||
Alle Services stellen ihre API in Form einer OpenAPI Spezifikation zur Verfügung. Diese Dateien liegen den Assets | ||
der jeweiligen Releases bei. | ||
|
||
![Übersicht über Release von wls-eai-service Version 0.0.1-RC1](/screenshot-wls-eai-service-release-0.0.1-RC1.png) | ||
*Übersicht über [Release](https://github.com/it-at-m/Wahllokalsystem/releases/tag/wls-eai-service%2F0.0.1-RC1) von | ||
wls-eai-service Version 0.0.1-RC1* | ||
|
||
___ | ||
|
||
Mithilfe dieses `openapi.json`-Releasefiles erfolgt die Generation des Datenmodells und der Client-API im | ||
[Backend](/technik/guides/api-client-generation/how-to-create-client-from-open-api-json.md) über ein Maven-Plugin, | ||
während im [Frontend](/technik/guides/api-client-generation/generate-client-from-openapi-json-frontend.md) CLI-Befehle | ||
zum Einsatz kommen. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
dist | ||
node_modules | ||
node_modules | ||
|
||
src/api/wls-clients/generated-*-api | ||
src/resources/openapis |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", | ||
"spaces": 2, | ||
"generator-cli": { | ||
"version": "7.10.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.