Combining multiple API calls into an NgRx Effect

Kent Walker
Upstate Interactive
5 min readFeb 12, 2019

I was working on an Angular project recently where I needed to combine multiple Rest API calls to retrieve data from a local database. Some of these API calls were dependent on other API calls so I needed a way to combine calls and pass the data returned to other calls. Each of these API calls returned an Observable so I needed a method for combining these observables and keeping them in an order that allowed me to get the result I wanted, which was single API call that was dependent on multiple separate API calls.

To add to this complexity, I was also using Angular’s implementation of the RxJS framework, NgRx, to manage the state of my application. Luckily for me, NgRx provides a central data store that can hold the data returned from API calls. So by using the store and some helpful RxJS operators, namely switchMap, withLatestFrom, and forkJoin, I was able solve my issue of combining multiple observables in a single NgRx effect and retrieving the data I needed. I’ll now discuss how I was able to accomplish this so that, in the future if you’re faced with a similar situation, you’ll have a good idea of what to do.

So what is an NgRx Effect anyway?

I’m assuming if you’re reading this article that you already some knowledge of the Redux state management pattern in Angular (called NgRx) and NgRx effects, there are many articles online to give you a thorough explanation of both. However, I’ll briefly summarize what state management is and how effects are used. Redux state management is about managing the entire state of an application on a single object so everything that happens, from a user entering data in a form to a call being made to a server to retrieve some data, is stored in a central repository (object) called the NgRx store.

So what are NgRx effects and how are the used in state management? An effect is an observable that “listens” for specific action types in the application’s actions’ stream which is also an observable. Effects typically handle any actions that involve any external interaction, such as network requests, web socket messages and time-based events. When a specific type of action occurs, such as requesting data from a database, the effect will make the call to the API service then return the data as the payload for a new action which it creates and publishes to the actions’ observable stream.

Creating the effect to handle multiple API calls

For my situation, the NgRx effect I needed to create depended on some data added to the store as the result of another effect which handled a “GET” action. So I decided to have my new effect listen for a specific “GET_COMPLETE” action which would be dispatched by the first effect if it successful retrieved the data and added it to the store. The reason I needed to chain these effects together is because I needed to use some of the data returned from the first effect to make the API calls in the second effect. And if the “GET_COMPLETE” action has occurred, then the data I need should’ve been retrieved from the server and placed in the store which I can now use in my new effect.

To gain access to the data in the store, I’ll import “Store” from the “@ngrx/store”:

import { Action, Store } from '@ngrx/store';

We also need to inject the store into our class constructor as shown here:

constructor(private actions$: Actions,private store: Store<State>,

Next, we add “@Effect()” which is a decorator that allows us to define a new effect:

@Effect()

Then we define the effect:

getUserTypeUserPermissions$: Observable<Action> = this.actions$.pipe(ofType<GetUserTypeComplete>(UserTypesActionTypes.GET_USER_TYPE_COMPLETE),withLatestFrom(this.store),

*Note: The name of the effect is arbitrary but you should add the $ at the end because this naming convention for observables.

I gave our new effect a type of Observable<Action> because, as I already mentioned, effects return actions which are observables. Next, I use the pipe operator on this.actions$ because it allows me to transform data that’s received with RxJS operators, like ofType, which in this instance, listens for the “GET_COMPLETE” action. I then use the withLatestFrom operator to combine the GetUserTypeComplete action with the latest values in the NgRx store because I will need to use data from the store in subsequent API calls (more information on withLatestFrom can be found here).

Using the switchMap and forkJoin operators to add multiple API calls

Now, we have a copy of the NgRx data store and the GetUserTypeComplete action that will be combined into one observable. We won’t need the data from the action but we will need the data from the store for multiple API calls. To achieve this, I will use switchMap, which is an RxJS operator that allows us to map the values emitted from one observable to a new observable (returning them as an array of values) and then cancel the old observable. Next, I’ll use the forkJoin operator to combine multiple observables which allows me to make multiple API calls as you can see below:

switchMap(([action, store]) => {return forkJoin(
of(store),
this.userTypes.getUserTypeSpecialPermissions(),
this.userTypes.getUserTypeSpecialPermissions({
where: { id: store.userTypes.selectedUserTypeId}
})
)
}),

forkJoin is an operator that waits for all observables passed to it to complete then takes the values emitted and emits them as an observable with an Array type (more information on forkJoin can be found here).As you can see in the example above, I also use another RxJS operator called of, to create an observable from a copy of the NgRx store which allows me to pass it, along with the results from the API calls (getUserTypeSpecialPermissions) to another switchMap.

switchMap(([storeState, allUserTypeSpecialPermissions, selectedUserTypeSpecialPermissions]) => {const filter = this.userTypesFilterService.getFilterWhere(storeState.userTypes.selectedUserTypePermissionLevel,allUserTypeSpecialPermissions, selectedUserTypeSpecialPermissions);return this.userPermissions.getUserPermissions({ filter: filter, pageNumber: '', pageSize: '' });}),

This switchMap cancels the previous observable and emits the values as an array which I destructure using ES6 syntax and pass to a function that calls a service to do processing on the data passed in from the previous API calls and then do another API call which produces a new observable (more information on switchMap can be found here).

Completing the Effect with a new Action

Finally, we complete our effect by taking observable from the last API call and passing it to the RxJS operator, map, which as its name indicates will map over the returned values and apply a function to it (more information on map can be found here).

map((res) => {return new GetUserPermissionsComplete(res);}));

In our case, the function is a new GetUserPermissionsComplete action which takes the value returned as a payload. The reducer will handle this action by adding the payload to the store and then we can create a selector to grab that data so we can use it in our application. And that’s it, we were able to chain together multiple API calls using RxJS operators and the NgRx store to get the data we needed. I hope this guide was helpful and showed you how you can leverage RxJS and NgRx to solve complicated problems, especially those involving retrieval of asynchronous data and using that data in other asynchronous actions.

The right software can change EVERYTHING. Interested in learning more?

--

--