1

I have an API endpoint that's returning an array of strings (json) and I'm trying to create a page that spits out the contents via an Angular Service. Here's what I have thus far (I'm on Angular 7):

export class FieldService {
  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<any[]> {
    return this.httpClient.get<any[]>(this.fieldTypesURL)
    .pipe(map((response: any) => response.json()),
      catchError((error: any) => Observable.throw(error.json().error || 'Server error')));
  }
}

The compilation error I'm getting is the following:

Type 'Observable<any[]>' is missing the following properties from type 'Promise<string[]>': then, catch, [Symbol.toStringTag], finally

Why is it mentioning a Promise here while I'm trying to use an Observable? Any ideas welcome!

dylst
  • 689
  • 8
  • 15

4 Answers4

1

When you are using httpClient, it automatically parses the response as JSON. So, the .pipe(map((response: any) => response.json()) could be the error here.

Also, type 'any' changed to 'string'

Give this a shot:

public getTypes(): Observable<string[]> {
return this.httpClient.get<string[]>(this.fieldTypesURL)
  .catch((error: any) => Observable.throw(( error && JSON.parse(error).error) || 'Server error')));
}

The .json() function does almost* the same thing as can be seen here Angular Response.json() not documented

Hamza Khan
  • 107
  • 1
  • 11
Dhananjai Pai
  • 5,914
  • 1
  • 10
  • 25
  • I simplified the code by removing that line and end up with a much nicer version, but I'm still running into the exact same error. I've tried a ton of variants recommended from this post with no luck either: https://stackoverflow.com/questions/37208801/property-map-does-not-exist-on-type-observableresponse – dylst Feb 05 '19 at 05:14
  • Sorry about that. See above. – dylst Feb 05 '19 at 05:15
  • public getTypes(): Observable { return this.httpClient.get(this.fieldTypesURL); } ... is my current code and it's throwing the same error. – dylst Feb 05 '19 at 20:30
0

@hamzakhan rightly said that we don't need to parse the response as json. But as your code is still not working try this I have just changed Observable to Observable in return type of function getTypes(). Hope it works good luck..!!!!!

export class FieldService {
  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<any> {
    return this.httpClient.get(this.fieldTypesURL)
    .pipe(map((response: any) => console.log(response),
      catchError((error: any) => Observable.throw(( error && JSON.parse(error).error) || 'Server error')));
  }
}
Deepankar Singh
  • 193
  • 1
  • 13
0

1) Calling httpClient with a generic argument makes the json conversion and type cast for you.

2) Observable#throw has been deprecated, use the throwError operator instead. Also, make sure you parse & handle your error correctly. Having a type for your error will definitely increase the type safety.

3) Make sure you call your service method correctly...

// field.service.ts
export class FieldService {

  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<string[]> {
    return this.httpClient.get<string[]>(this.fieldTypesURL).pipe(
      catchError((r: HttpErrorResponse) => throwError(r.error || 'Server error'))
    );
  }
}
// your.component.ts
export class YourComponent {

  constructor(private fieldService: FieldService){}

  // ... component logic ...

  public types: string[];
  public types$: Observable<string[]>;

  public callService() {

    // A correct call
    this.fieldService.getTypes().subscribe(types => this.types = types)

    // Also a correct call with a bit of observable stream processing
    this.types$ = this.fieldService.getTypes().pipe(
      catchError((err: any) => {
        // Component-side error processing can be put here
        return throwError(err);
      }),
      flatMap(types => types),
      filter(type => !!type),
      map(type => type.trim()),
      toArray()
    );

    // Incorrect calls (compiler errors)
    this.fieldService.getTypes().then(types => /* whatever */);
    this.fieldService.getTypes().catch(err => /* whatever */);
    let r: Promise<string[]> = this.fieldService.getTypes();
  }
}

Hope this helps a little :-)

Heehaaw
  • 2,677
  • 17
  • 27
0

Use the following code as catchError(this.handleError) will take care of your errors as well as failed Http requests.

export class FieldService {
  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<any[]> {
    return this.httpClient.get<any[]>(this.fieldTypesURL)
    .pipe(
      catchError(this.handleError)
    );
  }

  private handleError(error: HttpErrorResponse) {

    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.log('An error occurred:', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.log(
        `Backend returned code ${error.statusText}, ` +
        `body was: `,error.message);
    }
    // return an observable with a user-facing error message
    return _throw('Something went wrong. Please try again later.');
  };
}

If you notice, I removed .map() from the code just because it was used to perform some action on the response data, which is not required.

Todarmal
  • 306
  • 1
  • 12