API Mock für Angular

Thorsten Rintelen

Seit über 20 Jahren Software-Developer, Spezialisiert auf Angular, Teamleiter Entwicklung bei der traperto GmbH

Was wäre das schönste und schnellste Frontend ohne ein Backend? Richtig, es wäre schön und schnell. Wir wissen aber auch alle, dass zu einer guten Anwendung mehr gehört, als nur ein schönes und schnelles Frontend.
Dennoch wollen wir im Frontend, insbesondere während der Entwicklung, nicht abhängig vom Backend sein.

Was tun, wenn die Entwicklung des Frontend begonnen wird und noch keine Schnittellen zum Backend existieren?
Oder wenn wir Änderungen an Schnittstellen testen wollen, diese aber noch nicht vom Backend geliefert werden?
Oder wenn das Backend auf unserem Rechner gerade nicht laufen will bzw. mir die passende Datenbank fehlt?

Mock-Daten

Die Lösung ist eigentlich relativ einfach, wir brauche Mock-Daten.
Mock-Daten sind statische Daten, die wir in unserer Anwendung verwenden können. Anstatt Daten vom Backend über Schnittstellen zu laden, verwenden wir die statische Version von Daten. In der Regel ein JSON-Objekt aus einer REST-Schnittstelle.

Angular Lösungen

In Angular gibt es verschiedene Möglichkeiten, diese Daten zu verwenden. Die einfachste Variante wäre es, den Service zu finden der die Daten lädt, und an dieser Stelle direkt ein JS-Objekt zu verwenden. Wahlweise als Objekt oder als Observable.

getData(): Observable<Data> {
    return of({data: 'object});
 
    return this.httpClient.get<Data>(
        `https://example.org/rest/provision`,
    );
}

Funktioniert. Ist es aber ratsam, irgendwo im Code einen funktionierenden Service zu ändern und mit Mock-Daten zu versehen? Nein. 

Daher bietet Angular eine weitere Möglichkeit. Wir erstellen einen neuen Service, der ausschließlich für die Lieferung der Mock-Daten verantwortliche ist und nutzen den großen Vorteil der Dependency Injection (DI) von Angular. 
Wir überschreiben den DataService mit dem MockDataService, so dass an allen Stellen wo der DataService injected wird, der MockDataService verwendet wird.

// Methode im Service
getData(): Observable<Data> {
    return of({data: 'object});
}
 
// Module
@NgModule({
    declarations: [AppComponent],
    imports: [
        BrowserModule,
        AppRoutingModule,
    ],
    providers: [{
        provide: DataService,
        useValue: MockDataService
    }],
})
export class AppModule {}

Funktioniert auch. 

Ein Nachteil ist es, dass in einem Service mehr passieren kann, als nur Daten zu laden.
Was ist, wenn nach dem Laden der Daten diese noch aufbereitet werden und durch 12+ RxJS Operatoren verändert werden?
Oder im Service noch andere Methoden vorhanden sind?

Bei der Erstellung des MockDataService müssen wir diese ggf. ebenfalls kopieren. Unschön.

API Mock for Angular

Daher stelle ich gerne dieses NPM Paket bereit. Über dieses Paket können ganz gezielt einzelne Schnittstellen überschrieben werden. Wenn eine dieser Schnittstellen angesprochen wird, wird kein Request an das Backend gefeuert, sonder ein statischer Wert. z.B. ein JS-Objekt zurück gegeben.
Dazu wird das NgxApiMockModule importiert, wodurch ein Interceptor registriert wird, der auf die Requests lauscht. Findet dieser einen Übereinstimmung, so werden die statischen Daten zurückgegeben.

@NgModule({
  imports: [
    NgxApiMockModule.forRoot({
      urlParts: ['thorsten-rintelen.de/v1/'],
      rules: [
        {
          pattern: 'users/\\d+',
          response: 'success',
          method: 'POST',
        },
        {
          pattern: 'users/\\d+',
          response: true,
          method: 'DELETE',
        },
      ],
    })
  ]

Fazit

Wenn ich meine Schnittstellen mocken möchte, verwende ich NgxApiMock, um mit möglichst wenig Änderungen und ohne doppelten Code in einem Service ganz gezielt einzelne Schnittstellen zu mocken.
Klingt einfach, ist auch so.