i have a problem with https://github.com/HackerNews/API.
I need fetch all best news in Angular 7, on 30 news in first page(title, author...). How can i sent get request with next api?
This API show all Id of best story: https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty
This api show example of one story: https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty
I try this:
loadItem(){
this.http.get(`https://hacker-
news.firebaseio.com/v0/item/${this.id}.json?print=pretty`).subscribe(data => {
this.items.push(data as any[]);
})
}
loadBestItems(){
this.http.get('https://hacker-news.firebaseio.com/v0/beststories.json?
print=pretty').subscribe(data => {
this.bestItems.push(data as any[]);
})
}
I need 30 best news on first page
This is a bit of a loaded question, but I think we can break it down into three main questions:
1. How do you limit the number of stories returned by the hacker news api?
Since the hacker-news data is exposed through the firebase API, lets refer to the firebase docs. As indicated here, we can use the limitToFirst and orderBy options together to limit the number of results. We can simply order by the key, so your request URL would end up looking something like this:
'https://hacker-news.firebaseio.com/v0/beststories.json?
print=pretty&orderBy="$key"&limitToFirst=30'
2. How do you chain HTTP requests in Angular (make a second request that depends on the result of the first)?
This can be achieved with the mergeMap
rxjs operator. This operator allows you to map the values emitted by an observable to another observable. To simplify things, imagine your initial request was to only return a single id. We could then use mergeMap
to map the id to a request for the full item.
If that endpoint existed at the path beststory.json
, it would look something like this.like this:
this.http.get('https://hack...v0/beststory.json').pipe(
mergeMap((id) => this.http.get(`https://hack.../v0/item/${id}`))
).subscribe((data) => {
console.log('Story: ', data);
}
Since you need to map to multiple requests, however, we will need to introduce another operator, outlined in question 3.
3. How do you make multiple HTTP requests at the same time (make a request for each item in a list)?
This can be achieved with the forkJoin
rxjs operator. This operator takes an array of observables, and emits an array of their values once they are all complete. In the context of your problem, the input is an array of requests (one for each id in the initial request), and the output would be a list of items. To simplify things again, lets assume you already have an array of ids sitting around. Issuing requests for each item in the list would look something like this:
let ids = [1, 2,...];
forkJoin(ids.map((id) => this.http.get(`https://hack.../v0/item/${id}`)).subscribe((stories) => {
console.log('Stories:', stories);
});
Putting it all together
Now that we know how to map the result of a request to another observable with mergeMap
, and we know how to combine the results of multiple observables into one with forkJoin
, we can use them together to achieve what you're looking for:
this.http.get('https://hack....v0/beststories.json?orderBy="$key"&limitToFirst=30').pipe(
mergeMap((ids) => forkJoin(ids.map((id) => this.http.get(`https://hack...v0/item/${id}`)))),
).subscribe((stories) => {
console.log('Stories:', stories);
});
Note that in the code snippets I have excluded part of the url and unrelated query params