2/11/19

Handle nested requests with rxjs

In the previous post i manage to get data using nested requests - by vanilla javascript.
In this post I will try to explain how to do the same thing, but using angular + rxjs library.
Firstly - lets write here the usual angular service which has "getUsers" and "getRepos" methods:

import { HttpClient,  HttpErrorResponse } from '@angular/common/http';
import { Observable} from 'rxjs';
import { from } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  token = 'PUT-YOUR-TOKEN-HERE';
  constructor(private http: HttpClient) { }
  
  getUsers(since=0) : Observable {
    return this.http.get(`https://api.github.com/users?per_page=10&since=${since}&access_token=${this.token}`)
      .pipe(
        catchError(this.handleError('getUsers'))
      ) as Observable;
  }

  getReposCount(user) : Observable {   
    return this.http.get(`https://api.github.com/users/${user}/repos?per_page=10000&access_token=${this.token}`)
      .pipe(
        map(repos => repos.length || 0 ),
        catchError(this.handleError('getReposCount'))
      ) as Observable;
  }
  ...
  ...
}

But how to combine those two requests to work together as nested requests?
After googling around I came up with following code:

  getData(since) {
     return this.getUsers(since)
       .pipe(
         concatMap(users => from(users)),
         mergeMap((user) => this.getReposCount(user.login)
            .pipe(
              map(count => ({login: user.login, avatar: user.avatar_url, count}))
            )         
         ),
         toArray()
       )
  }
What a mess! - What is "form"? What are those "concatMap" and "mergeMap"? and why this "toArray" needed?
I will try to understand myself

Big Picture (as i understood so far)

The big picture of what is need to be done here - is:
* We need to convert the stream which brings as a collection to stream which brings us single user (one by one)
* For each user we need to send the request to get repos count and update the user object
* Stream of single users need to be converted back to stream of arrays


concatMap

according to the docs: Map values to inner observable, subscribe and emit in order (same as mergeMap but preserves the order)

from

according to this article - converts an array to an observable. - need for converting the observable of users array to observable of single users

mergeMap

Map to observable, emit values

why not switchMap?

In many examples, demonstrating how to do some operation on the stream - the "switchMap" method is widely used:


  getQuote(): Observable {
    return Observable.create(observer => observer.next(this.nextId++)).pipe(
      // here
      switchMap((id: number) => this.http.get(`api/quotes/${id}`)),
      map((q: Quote) => q.quote),
      ...
    )
SwitchMap is also maps the observable to different one , however - the main feature of switchMap is that it "kills" the previous observable, thus it cannot fit for our case...

No comments:

Post a Comment

Getting started with docker

It is very simple to get started usig docker. All you need to do-is download the docker desktop for your system Once you get docker syste...