0

I am proficient with Angular 1.x/Promises, but totally new to Angular5/Observables. With Angular 1 and Promises, we are able to intercept the HTTP response to an API, do some specific logging with the HTTP response, and then pass back the actual data returned to the caller using a new deferred Promise. The caller then resolves the Promise to get the returned value(s).

I want to do something similar with Angular 5, but I am getting hung up with Observables. I can't seem to figure out how to get the HTTP response, log it or the error, and then propagate the response data back to the caller, with either the data or an error.

EX:

The 'base' function calls the HttpClient 'request' function. I was hoping to subscribe here to do some logging, and then return perhaps a new Observable to pass back, especially if the call succeeds.

base<R>(method: string, url: string) {
    const _headers = new HttpHeaders();
    const headers = _headers.append(this.CONTENT_TYPE_HEADER, this.CONTENT_TYPE)
      .append(this.AUTH_HEADER, (this.AUTH_TYPE + TokenMgrService.UserJwt));

    return this.http.request<R>(method, url, { headers: headers, observe: 'response' }).subscribe(
      (res: HttpResponse<R>) => {
        // Do some detailed logging here...
        return res.body;
      },
      err => {
        // Do some error logging here...
        return null;
      });
  }

The 'get' function is a simple wrapper around the 'base' function. The plan is to support other methods (POST, PUT, DELETE) in a similar manner.

  get<R>(url: string) {
    return this.base('GET', url);
  }

The 'getFoo' is an example of the function that would be in an application/API specific service. I would provide the template type and call the 'get' wrapper function.

  getFoo(foo_id: number) {
    return this.get<Foo>('https://hostname/v1/foos/' + foo_id);
  }

I would like the caller to 'getFoo' to be able to subscribe to get the result or error....or do I...am not sure.

  // Caller
  getFoo(111).subscribe(
    res => {
      // WAT!?
    }
  );

The function 'getFoo' is choking because 'subscribe' does not exist on the returned Subscription that originated in the 'base' function.

Obviously, I'm way off base ...can someone point me in the right direction? Thanks.

5
  • You shouldn't subscribe inside the method that returns an observable. use do operator. Also, that's what interceptors are for. Commented Mar 16, 2018 at 18:47
  • Thanks, i'll check out the 'do' operator. I was trying to stay away from HTTP interceptors, but may go that with that (assuming you are referring to HTTP interceptors). Commented Mar 16, 2018 at 18:48
  • Yes. It always depends if they are needed, but since you're after the behaviour that may be applicable globally like logging, this may be the case. Commented Mar 16, 2018 at 18:54
  • What you are looking for is angular pipes angular.io/guide/pipes Commented Mar 17, 2018 at 3:04
  • I'm not sure how Angular pipes are going to be of benefit here. Not all of the data returned will be directly mapped to a template but instead used to drive business logic. But I'll take a look again..thanks! Commented Mar 17, 2018 at 3:52

1 Answer 1

2

I figured it out...at least the specific issue I was trying to resolve. I had to make the following changes in the example:

base<R>(method: string, url: string): Observable<R> {
    const _headers = new HttpHeaders();
    const headers = _headers.append(this.CONTENT_TYPE_HEADER, this.CONTENT_TYPE)
      .append(this.AUTH_HEADER, (this.AUTH_TYPE + TokenMgrService.UserJwt));

    return this.http.request<R>(method, url, { headers: headers, observe: 'response' }).do(
      (res: HttpResponse<R>) => {
        // Do some detailed logging here...
        console.log(res.statusText);
      },
      err => {
        // Do some error logging here...
        console.log(err);
      })
      .map((res: HttpResponse<R>) => { return res.body; });
  }

Added the 'do' and 'map' operator, per estus' suggestion. The 'do' allows me to tap into the Observable without subscribing so I can do some specific logging (will be sending log data to Elasticsearch in the future for tracing). The 'map' allows me to convert the request Observable< HttpResponse< T>> to just Observable< T> to strip out HTTP metadata from the response before I pass along to the caller.

  get<R>(url: string): Observable<R> {
    return this.base('GET', url);
  }

Had so explicitly return Observable< R>.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.