Skip to content

task#12 load data from api

bacn edited this page Sep 16, 2020 · 1 revision

Load data from local API

  1. Inject Http via constructor(private httpClient: HttpClient) in AuctionDataService
  2. Load data from local API in AuctionData service via httpClient.get(...)
  3. Install the test-auction-api with npm install -g test-auction-api
  4. Use an HttpInterceptor to create the correct date tyoe from a json date string.

Result

Start the test-auction-api server in a second console with

$ test-auction-api

Check the test-auction-api Server in the browser by entering http://localhost:4730/auctions. An instruction is displayed at url [http://localhost:4730] (http://localhost:4730)

Compile and start the application with

$ ng serve

Open project in browser


task9-result.png


Hints

Install the test server

$ npm install -g test-auction-api

Start the test-auction-api server in a second console with

$ test-auction-api 

The server write a confirmation: JSON Server is running on port 4730

File auction-data.service.ts

Add a new method getHttpAuctions() and return an observable with the JSON-Data.

import { Injectable } from '@angular/core';
import {Auction} from './auction';
import {AUCTION_DATA} from './auction-data';
import {Observable, of} from 'rxjs';
import {HttpClient} from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AuctionDataService {

  private auctions: Auction[] = AUCTION_DATA;
  private URL = 'http://localhost:4730/auctions';

  constructor(private httpClient: HttpClient) {}

  public getAuctions(): Auction[] {
    return this.auctions;
  }

  getObservableAuctions(): Observable<Auction[]> {
    return of(this.auctions);
  }

  public getHttpAuctions(): Observable<Array<Auction>> {
    return this.httpClient.get<Array<Auction>>(this.URL);
  }

}

The result will map correctly except the date. Because of the lack of a standard JSON date format, the date/time/Zone information is not correctly deserialized. The result will be a date which is nothing else but a string.

The AngularDateHttpInterceptor interceptor is automatically called for each HttpRequest to change date strings in date types.

File auction-list.component.ts

Change the method to getHttpAuctions().

  ngOnInit() {
    this.auctionsObservable = this.auctionDataService.getHttpAuctions();
    this.auctionSubscription = this.auctionsObservable.subscribe(data => this.auctions = data);
  }

New File angular-date-http-interceptor.service.ts

Generate with ng-cli:

$ ng generate service shared/angular-date-http-interceptor

Unfortunately, all dates in the JSON are parsed as strings in the resulting object. If the key is a date string a new Date() type is created. Create a new file src/shared/angular-date-http-interceptor.ts and copy paste the interceptor.

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpErrorResponse,
  HttpResponse
} from '@angular/common/http';
import { tap } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AngularDateHttpInterceptorService implements HttpInterceptor {
  // Migrated from AngularJS https://raw.githubusercontent.com/Ins87/angular-date-interceptor/master/src/angular-date-interceptor.js
  iso8601 = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/;

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(tap(
      (event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          const body = event.body;
          this.convertToDate(body);
        }
      },
      (err: any) => {
        if (err instanceof HttpErrorResponse) {
          if (err.status === 401) {
          }
        }
      }
    ));
  }

  convertToDate(body) {
    if (body === null || body === undefined) {
      return body;
    }

    if (typeof body !== 'object') {
      return body;
    }

    for (const key of Object.keys(body)) {
      const value = body[key];
      if (this.isIso8601(value)) {
        body[key] = new Date(value);
      } else if (typeof value === 'object') {
        this.convertToDate(value);
      }
    }
  }

  isIso8601(value) {
    if (value === null || value === undefined) {
      return false;
    }

    return this.iso8601.test(value);
  }
}

File app.module.ts

The new interceptor AngularDateHttpInterceptor needs to be declared as a provider of type HTTP_INTERCEPTORS.

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {AuctionListComponent} from './auction-list/auction-list.component';
import {MouseEventDisplayComponent} from './mouse-event-display/mouse-event-display.component';
import {HTTP_INTERCEPTORS, HttpClientModule} from "@angular/common/http";
import {AuctionDataService} from "./shared/auction-data.service";
import {AuctionListDetailComponent} from './auction-list-detail/auction-list-detail.component';
import {AngularDateHttpInterceptor} from "./shared/angular-date-http-interceptor.component";

@NgModule({
  declarations: [
    AppComponent,
    AuctionListComponent,
    MouseEventDisplayComponent,
    AuctionListDetailComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AngularDateHttpInterceptorService,
      multi: true
    }, AuctionDataService],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Analyse the data transfer

Open the browsers developer tools -> tab network. Search for the auction request at the test-auction-api

test-auction-request.png


The delivered data in detail:

test-auction-answer-data.png


The iso8601 date format e.g. endDateTime: "2020-05-02T11:12:34.511Z" is converted into a javascript date.

https://de.wikipedia.org/wiki/ISO_8601

Clone this wiki locally