Angular + OpenAPI Generator

In einem älteren Posting haben wir schon einmal einen Blick auf Swagger geworfen, eine charmante Möglichkeit aus den eigenen Rest-Schnittstellen eine technisch auswertbare OpenAPI Beschreibung zu generieren. Swagger bietet neben dieser Core-Möglichkeit noch eine ganze Reihe mehr, z.B. die Generierung von Client-Stubs. Das entsprechende Projekt ( Codegen ) wurde gefühlt eine ganze Zeitlang nicht aktiv verfolgt. Inzwischen lebt die Idee in einem Community getriebenem Projekt weiter: OpenAPI Generator. Werfen wir einen kurzen Blick auf die Verwendung im Zusammenspiel mit Angular.

Die Open API Spezifikation ist eine Standardbeschreibung für Schnittstellen die im JSON oder YAML Format Rest Schnittstellen (inklusive URL, Authentifizierung und Datenmodell) beschreibt. Eine Verwendungsmöglichksit ist die Generierung von Client-Code der die Entwicklung z.B. eines Anuglar-Clients erleichtert.

Der OpenApi Generator bietet hierbei unter anderem mit einem NPM-Tool welches ganz einfach per Kommandozeile installiert werden kann

npm install @openapitools/openapi-generator-cli -g

ein einfacher Aufruf zur Generierung von Angular-Sourcen könnte dann so aussehen:

openapi-generator generate -g typescript-angular -o src/app/api -i ./openapi.json

auf Basis der übergebenen API Spezifikation werden nun entsprechende Type-Script Sourcen generiert für

unsere Model-Klassen:

/**
 * The version of the OpenAPI document: 3.2
 *
 * NOTE: This class is auto generated by OpenAPI Generator 
(https://openapi-generator.tech).
 * Do not edit the class manually.
 */


export interface Project { 
    id?: number;
    projectId?: string;
    projectName?: string;
}

und eine zentrale Service-Klasse, die solche Methoden entsprechend unserer Resourcen generiert (unter Berücksichtigung von Pfadparametern und Rückgabewerten) (vereinfachte Darstellung):

public getAllProjects(limit?: number, first?: number): Observable<Project[]&gt; {
    ...
        return this.httpClient.get<Array<Project&gt;&gt;(`${this.configuration.basePath}/resources/project`,
            {
                params: queryParameters,
                withCredentials: this.configuration.withCredentials,
                headers: headers,
                observe: observe,
                reportProgress: reportProgress
            }
        );
    }

Was nun lediglich noch fehlt für den Projektalltag ist die

  • Konfiguration der Base-URL, vorzugsweise über einen Provider, hier z.B. über die environmen.ts
@NgModule({
 ...
  providers: [
    {
      provide: BASE_PATH,
      useValue: environment.baseurl
    }
  ]
  ...
  • Login Credentials über HTTP-Interceptor hinzufügen
@Injectable({
  providedIn: 'root'
})
export class HttpJwtInterceptorService implements HttpInterceptor {
  constructor(private loginService: LoginService) {}

  intercept(req: HttpRequest<any&gt;, next: HttpHandler): Observable<HttpEvent<any&gt;&gt; {
    const token = this.loginService.token;

    if (token) {
      req = req.clone({
        setHeaders: {
          Authorization: 'Bearer ' + this.loginService.token
        }
      });
    }
    return next.handle(req);
  }
}


// + Registrierung im Modul
@NgModule({
 ...
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      multi: true,
      useClass: HttpErrorInterceptorService
    }
  ]
  ...

Grundsätzlich eine sehr coole Sache, die uns viel Tipp-Arbeit spart. Im Hinterkopf sollte man aber immer behalten das wir damit unser Projekt auf zwei Generatoren stützen: 1) Swagger-Core um unsere OpenAPI zu generieren und 2) OpenAPI Generator um unsere Angular Artefakte erstellen zu lassen . Hier werden wir über kurz oder lang bei „komplexeren“ Schnittstellen an den Punkt kommen an dem einer der Generatoren nicht mehr das liefert was wir uns wünschen. Hier heißt es dann gegebenenfalls „händisch“ nach zu arbeiten. Eine Möglichkeit im Anuglar: generell mit einem Service-Delegate arbeiten: damit zentralisieren wir den Zugriff auf die generierten Teile unserer Anwendung und können hier auch zusätzliche Funktionalitäten implementieren ( z.B. „Caching“) und fachliche Gruppen („ProjektService“, „CustomerService“) ausprägen, auch wenn das wieder ein klein wenig Tipparbeit ist 😉

@Injectable({
  providedIn: 'root'
})
export class ProjectService {
  private projects: Project[];

  constructor(private service: DefaultService) {
  }

  getAll(limit?: number): Observable<Project[]&gt; {
    if (!this.projects) {
      return this.service.getAllProjects(limit).pipe(tap(r =&gt; (this.projects = r)));
    } else {
      return from([this.projects]);
    }
  }
}
Werbeanzeigen

Über Dominik Mathmann
Dominik Mathmann arbeitet als Berater, Entwickler und Trainer bei der GEDOPLAN GmbH. Auf Basis seiner langjährigen Erfahrung in der Implementierung von Java-EE-Anwendungen leitet er Seminare, hält Vorträge und unterstützt Kunden bei der Konzeption und Realisierung von Webanwendungen vom Backend bis zum Frontend. Sein derzeitiger Schwerpunkt liegt dabei auf der Entwicklung von JSF-Anwendungen. Er sieht die stärker werdende Position von JavaScript-Frameworks jedoch positiv und beschäftigt sich darüber hinaus mit Webframeworks wie Angular.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

%d Bloggern gefällt das: