Generierung von Client APIs mit Swagger Teil 1

Mit jedem neuen Backend-Release müssen Frontend-Entwickler*innen große Teile des API-Clients neu schreiben. Was wäre, wenn es eine Lösung gäbe, um den gesamten Client in nur wenigen Sekunden zu aktualisieren?

Also available in English at Medium.com.

In diesem Blog-Post stellen wir die Client-Generierung von Swagger vor, zeigen, wie man die generierte API in React-Anwendungen verwendet und wie man das Authentifizierungs-Token von Auth0 integriert.

Der Einfachheit halber wird dieses Thema in eine dreiteilige Serie aufgeteilt:

  1. Teil 1: Integration von Swagger in Spring Boot, Generierung des API-Clients und Verwendung als Teil einer React-Web-App
  2. Teil 2: Sicherung der Endpunkte mit Auth0 und Autorisierung der Anfragen der Web-Clients
  3. Teil 3: Verwendung des generierten API-Clients als Teil einer React Native App.

Integration von Swagger in Spring Boot und Generierung des Clients

Ziel dieses Abschnitts ist es, die API-Dokumentation einer Java-Spring-Boot-Anwendung mit Swagger zu generieren, den entsprechenden TypeScript-Axios-Client zu erstellen, der die API-Aufrufe kapselt, und diesen Client in eine React-Web-App zu integrieren. Das Ergebnis wird wie folgt aussehen:

TL;DR

  1. Klonen Sie unser Beispiel-Backend, starten Sie Docker und führen Sie die Anwendung mit dem Spring-Boot-Profil no-security aus.
  2. Klonen Sie unsere Beispiel-Web-App, installieren Sie alle Abhängigkeiten mit yarn install und führen Sie yarn generate-api im Stammverzeichnis des Projekts aus.

Schritt 1) Integrieren von Swagger in Spring Boot

Alle Codeschnipsel sind Teil unseres Beispiel-Backends. Diese Backend-Anwendung ermöglicht die Verwaltung von Projekten, die jeweils den Namen eines Kunden und seine Adresse enthalten. Mit Hilfe der API-Endpunkte kann ein Nutzer Projekte erstellen, lesen, aktualisieren und löschen (CRUD).

1a) Kommentieren Sie die Controller und fügen Sie Metadaten über jeden Endpunkt hinzu

Nach dem Hinzufügen der Abhängigkeit springdoc-openapi-ui zur build.gradle bzw. pom.xml können Sie die darin enthaltenen Annotationen für die Projekt-Controller verwenden, um Metadaten hinzuzufügen:

@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@Tag(name = "Project Controller")
@RequestMapping("/api/project")
public class ProjectController {

    private final ProjectService projectService;
    private final ProjectApiMapper projectMapper;

    @Transactional(readOnly = true)
    @GetMapping
    @Operation(summary = "Get list of all projects")
    public ResponseEntity<List<ProjectTO>> getAllProject() {
        log.debug("Received request to load all projects");
        final List<Project> allProjects = this.projectService.getAllProjects();
        return ResponseEntity.ok(this.projectMapper.mapToTO(allProjects));
    }
...

1b) Besuchen Sie die generierte API-Dokumentation

  1. Wie in der ReadMe des Projekts beschrieben, müssen beide Docker-Dienste (nginx und postgres) laufen, bevor Sie das Beispiel-Backend starten können.
  2. Bitte stellen Sie sicher, dass Sie in den Run-Konfigurationen das Profil no-security aktiviert haben: IntelliJ → Run → Edit Configurations... → Active profiles: no-security
  3. Jetzt sollten Sie in der Lage sein, die API-Dokumentation in Ihrem Browser zu öffnen: http://localhost:8081/swagger-ui.html

Schritt 2) Den API-Client generieren

Es gibt mehrere Möglichkeiten, einen API-Client mit Swagger zu erzeugen: Sie können ein Gradle- oder Maven-Plugin verwenden, den Swagger-Editor oder eine JavaScript-Bibliothek eines Drittanbieters verwenden.

Unserer Meinung nach sollte die Generierung des API-Clients nicht Teil des Backends sein. Deshalb haben wir uns zunächst für den Swagger-Editor entschieden und haben später auf die Bibliothek openapi-generator-cli gewechselt, um die Vorteile von stark typisierten Schnittstellen in TypeScript zu nutzen.

In diesem Abschnitt werden wir beide Wege, den Swagger-Editor und die openapi-generator-cli, erläutern:

2a) Swagger-Editor

  1. Öffnen Sie die URL http://localhost:8081/v3/api-docs und kopieren Sie alles.
  2. Rufen Sie den Swagger-Editor (https://editor.swagger.io/) auf und fügen Sie die kopierte API-Beschreibung in das Editor-Fenster ein → Sie werden gefragt, ob Sie ihn in .yaml umwandeln wollen → Akzeptieren Sie.
  3. Im Menü des Swagger-Editors finden Sie das Dropdown-Menü "Generate Client". Wählen Sie "TypeScript Axios" und warten Sie, bis der Download abgeschlossen ist.
  4. Entpacken Sie es, kopieren Sie api.ts, base.ts, configuration.ts, apis-folder und models-folder in einen neuen Ordner in Ihrem Frontend-Projekt.

2b) openapi-generator-cli

  1. Fügen Sie @openapitools/openapi-generator-cli mit dem folgenden Befehl als dev-Abhängigkeit in Ihre Web-App ein:

    yarn add --dev @openapitools/openapi-generator-cli

  2. Vergewissern Sie sich, dass Ihr Backend gestartet ist und läuft.
  3. Führen Sie den folgenden Befehl aus:
yarn openapi-generator-cli generate \
    -i http://localhost:8081/v3/api-docs \
    -g typescript-axios \
    -o src/api

Optional: Löschen Sie die Dateien .npmignore, .gitignore und git_push.sh, und fügen Sie sie der Datei .openapi-generator-ignore hinzu. Fügen Sie openapitools.json und .openapi-generator zur Datei .gitignore Ihres Projekts hinzu.

Schritt 3) Verwendung des API-Clients in einer React-Webanwendung

Um mit der generierten API unter Verwendung von nginx als Reverse Proxy zu arbeiten, müssen Sie zuerst die BASE_PATH-Variable in src/api/base.ts auf einen leeren String setzen:

export const BASE_PATH = "";

Jetzt können Sie mit nur drei Zeilen Code Daten vom API-Endpunkt abrufen:

const projectController = new ProjectControllerApi();
const response = await projectController.getAllProject();
const data = response.data;

In unserer Beispiel-Web-App haben wir alle API-Aufrufe in einer Helper-Methode gekapselt, um Fehler abfangen zu können. Zusätzlich verwenden wir redux-store, um die empfangenen Daten zu cachen, was uns erlaubt, die Backend-Aufrufe zu reduzieren.

Im nächsten Teil der Serie werden wir uns damit beschäftigen, wie wir die API-Endpoints mithilfe von Auth0 absichern und die Anfragen unserer Web-App entsprechend autorisieren können. Bis zum nächsten Mal!