1

I have an API that returns this example payload -

    {
      "uid": "string",
      "queue": {
        "size": 0,
        "averageWaitTime": 0,
        "inChair": "string",
        "status": "OPEN",
        "customers": [
          {
            "uid": "1b3",
            "haircut": "SHAPE_UP",
            "hasBeard": true,
            "useScissors": true
          },
          {
            "uid": "1b2",
            "haircut": "SHAPE_UP",
            "hasBeard": true,
            "useScissors": true
          }
        ]
      }
    }

What I need to do before returning the response to the calling function, is loop through the customers [] and make further HTTP requests using the "uid" value in each object of the array to obtain extra data that needs to be appended to its respective object. So it would look something like this -

{
      "uid": "string",
      "queue": {
        "size": 0,
        "averageWaitTime": 0,
        "inChair": "string",
        "status": "OPEN",
        "customers": [
          {
            "uid": "1b3",
            "haircut": "SHAPE_UP",
            "hasBeard": true,
            "useScissors": true,
            "extra": {
                "name": "Fred",
                "telephone": "000"
            }
          },
          {
            "uid": "1b2",
            "haircut": "SHAPE_UP",
            "hasBeard": true,
            "useScissors": true,
            "extra": {
                "name": "Fred",
                "telephone": "000"
            }
          }
        ]
      }
    }

Here is what I have tried so far -

barberQueue(): Observable<BarberConfigurations> {
        return this.http.get<BarberConfigurations>( `${environment.apiEndpoint}/barber/profile` )
        .pipe(
            mergeMap( ( response: any ) => {
                return forkJoin(
                    response.queue.customers.map( customer => {
                        return this.customerService.get( customer.uid ).pipe(
                            map( resp => {
                                return {
                                    ...customer,
                                    extra: resp
                                };
                            } )
                        );
                    } )
                );
            } ),
        );
    }

This is returning just an [] of the customer objects. What I need is still to return the rest of the original payload in the correct structure. I don't think I am quite getting my head around some of the operators.

Can someone help me to understand where I am going wrong?

6
  • Take a look at this article. It should give you inspiration for this case as well as for similar http based cases where you want to leverage the power of rxjs Commented Dec 31, 2020 at 13:41
  • Try this: stackoverflow.com/questions/47617169/… Commented Dec 31, 2020 at 13:42
  • Look at this also stackoverflow.com/a/65464764/5699993 Commented Dec 31, 2020 at 13:43
  • Have you tried switchMap instead of mergeMap? Commented Dec 31, 2020 at 14:48
  • Yeah, this still only returns an array of customers rather than the original object with the updates customers array inside it Commented Dec 31, 2020 at 14:51

2 Answers 2

2

you just need to return a new observable for each customer with the help of mergeMap

    return this.http.get<BarberConfigurations>( `${environment.apiEndpoint}/barber/profile` )
    .pipe(mergeMap(customer => this.customerService.get( customer.uid )
    .pipe(map( resp => {
                            return {
                                ...customer,
                                queue: {
                                  customers: customer.queue.customers.map(c => ({...c, extra: resp}))
                                }
                                
                            };
                        }), take(1)  ) ));
Sign up to request clarification or add additional context in comments.

4 Comments

The customer exists in customers [] so how would i reflect that with the mergeMap?
maybe i misunderstood, what does this.http.get<BarberConfigurations>( ${environment.apiEndpoint}/barber/profile ) return
did you try this approach ? do you have any errors ?
It returns the first object example in my question
0

I think you're 99% of the way there. You've enriched customers with your extra data, now you just need a step to insert that enriched array back into your original payload.

function barberQueue(): Observable<any> {

  return this.http.get<BarberConfigurations>(
    `${environment.apiEndpoint}/barber/profile`
  ).pipe(
    mergeMap(barbConfig => 
      forkJoin(
        barbConfig.queue.customers.map(customer =>
          this.customerService.get( customer.uid ).pipe(
            map(resp => ({
              ...customer,
              extra: resp
            }))
          )
        )
      ).pipe(
        map(customers => {
          barbConfig.queue.customers = customers
          return barbConfig;
        })
      )
    )
  );

}

You can also separate out some of the logic to make your code a bit clearer

function barberQueue(): Observable<any> {

  const enrichCustomerService = customer =>
    this.customerService.get( customer.uid ).pipe(
      map(resp => ({
        ...customer,
        extra: resp
      }))
    );

  const enrichPayload = config => customers => {
    config.queue.customers = customers
    return config;
  }

  return this.http.get<BarberConfigurations>(
    `${environment.apiEndpoint}/barber/profile`
  ).pipe(
    mergeMap(barbConfig => 
      forkJoin(
        barbConfig.queue.customers.map(enrichCustomerService)
      ).pipe(
        map(enrichPayload(barbConfig))
      )
    )
  );

}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.