3
votes

I implemented an method which returns an Observable. Inside this method I am using http.post to send a request to the backend. After receiving the response, which is a JSON object, I want to store this in an Observable variable and return that variable. But somehow I didn't manage to solve that problem. In .subscribe the res variable is not stored in the postResponse variable, but I can see in the "local" console.log that the res variable has the correct value. The global console.log is empty. Furthermore I get the error:

"TS2322: Type 'ArqResponse' is not assignable to type 'Observable'" error for the return.

My code looks like this:

postARQRequest(request): Observable<ArqResponse>{
    let postResponse = new ArqResponse;
    const result = this.http.post<ArqResponse>(this.arqUrl, request)
                       .subscribe((res: ArqResponse) => { postResponse = res; console.log('shadow: ' + res)});
    console.log('global: ' + JSON.stringify(postResponse));
    return postResponse;
}

My questions are:

  1. How can I store the response body in a variable, which then can be returned?
  2. How can I "cast" an ArqResponse variable to an Observable variable?
  3. .subscribe seems to be wrong since I get:

this.arqService.postARQRequest(...).subscribe is not a function error

3

3 Answers

5
votes

I'm guessing this is what you want:

postARQRequest(request): Observable<ArqResponse>{
    return this.http.post<ArqResponse>(this.arqUrl, request);
}

There's no need to subscribe to anything here. Given that this.http.post returns the type you want, just return that.

If you really want to store the response in a local variable, there are some ways to do that:

Use a promise instead, for getting the result. Make it observable using of later on:

async postARQRequest(request): Observable<ArqResponse>{
    let postResponse = new ArqResponse;
    postResponse = await this.http.post<ArqResponse>(this.arqUrl, request).toPromise();

    return of(postResponse);
}

Use the tap operator to react to the response, but not mutate it

postARQRequest(request): Observable<ArqResponse>{
    return this.http.post<ArqResponse>(this.arqUrl, request).pipe(
        tap((res) => ...) // do stuff with res here, but it won't be mutated
    );
}

Use the map operator to map the response to something else

postARQRequest(request): Observable<ArqResponse>{
    return this.http.post<ArqResponse>(this.arqUrl, request).pipe(
        map((res) => ...) // do stuff with res here, but it *will map to whatever you return from this handler*
   );
}
1
votes

I think this may help you

postARQRequest(): Observable<ArqResponse[]> {
 return this.http.post(this.arqUrl, request)
 .map(this.extractData()) <== passing result of function
 .catch(this.handleError()); <== passing result of function
}

handle response and error here

private extractData(res: Response) {
   let body = res.json(); 
   return body.data || { }; 
}

private handleError (error: any) {
    let errMsg = error.message || 'Server error';
    console.error(errMsg); 
    return Observable.throw(errMsg);
}
0
votes

YThe method http.post already return an Observable, so you can directly do like that:

postARQRequest(request): Observable<ArqResponse>{
    return this.http.post<ArqResponse>(this.arqUrl, request);
}

and then subscribe to it: this.arqService.postARQRequest(...).subscribe()

If you want to transform an object to an Observable, you can use of from Rxjs6:

import { of } from 'rxjs';

// ...

// create an Observable from a value:
of(someObject);