Issue
Nestjs suggests to use the HttpModule
, imported from @nestjs/axios
to perform requests to external APIs.
I understand that the HttpService
transforms the responses into Observables
.
Goal
Request data from an external API and use the data inside the application.
Problem
I fail to understand how to actually retrieve the data from the request. I read in some other answers, that if you return the observable from a Controller
, Nestjs will automatically handle it for you and return the data to the client. That's great, however, I am not using it inside a Controller
. I need the data to be available inside the application.
I have a service:
@Injectable()
export class ExampleService {
// constructor
getData(): Observable<AxiosResponse<any[]>> {
return this.httpService.get(`http://some-url.com`);
}
}
How would use getData()
within the application logic to get to the data returned by the Observable
? And would it be better, in that case, to use a plain axios request with Promises
and not use the HttpModule
?
The only solution I found so far is using subscribe
:
this.httpService.get(`http://some-url.com`)
.subscribe((value) => {
console.log(value);
});
Which seems to be would end up in a callback hell, compared to all the fancy async ... awaits
.
Solution
The Answer
The only solution I found so far is using subscribe
Bingo. That's how it's done :)
Some Elaboration
Which seems to be would end up in a callback hell, compared to all the fancy async ... awaits
Not really. As a library built to be declarative, RxJS makes it easy to structure your callbacks.
async/await is just syntactic sugar for promise
s and .then
. It's a language feature, but even without async/await promises bind to one another nicely and avoid deep nesting and 'callback hell'
So while observables don't (and probably never will) enjoy fist-class language constructs like async/await
, that doesn't mean they won't manage some (or a lot) of complexity for you.
The RxJS library is built so that, generally, you should never have to nest subscriptions.
The following is considered an anti-pattern:
stream1().subscribe(value1 =>
stream2(value1).subscribe(value2 => {
/* Do something with value2 */
})
)
It would more idiomatically be written as:
stream1().pipe(
mergeMap(value1 => stream2(value1))
).subscribe(value2 => {
/* Do something with value2 */
})
Notice how a level of indentation is removed and you only need to subscribe once?
Observables come with a set of higher-order operators that act as highly customizable .then
s for streams of values instead of just individual values.
Another Way: Convert to Promises
Observables are a superset of promises, which means you can turn any promise into an observable but you lose structure if you want to convert an observable into a promise. Often this isn't an issue, but let me explain by analogy.
If promises are a container for a value, then observables are a container for a list of values.
I can take any value and create a list out of it. I'll just have a list of length 1.
a_value = 5
// convert with:
list_values = [a_value]
I can't take any list and create a value out of it. I can take the first value, or the last value (If there's only one, those might be the same), if the list is empty, maybe I need to throw an error? Maybe there's a default value I'd be happy with?
Maybe I have a way to reduce multiple values into a single value. Perhaps I can turn a list of integers into a value by adding them all together.
list_values = [1,2,3,4,5]
// convert with:
value = list_values[0] || 0
// or
value = list_values[list_values.length - 1] || 100
// or
value = sum(list_values)
Back to promises. RxJS has firstValueFrom
and lastValueFrom
as utility functions that wrap a promise around an observable.
firstValueFrom(
this.httpService.get(`http://some-url.com`)
).then(value => {
/* Do something with value */
});
// or with await as syntactic sugar
value = await lastValueFrom(
this.httpService.get(`http://some-url.com`)
);
/* Do something with value */
These are typically enough for something like an http request (since those only return a single value). More complex approaches tend me be handled on the RxJS side before being converted into a promise.
Answered By - Mrk Sef Answer Checked By - Marie Seifert (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.