I have 3 dependent Rest API resources (lets say observables) like this:
1st observable produces one item as array of users, like this:
getUsers(): Observable<User[]>
[
{
"id": 1,
"name": "Peter",
"surname": "Smith"
},
{
"id": 2,
"name": "John",
"surname": "Wayne"
},
...
]
2nd observable can be used to fetch addresses assigned to user, so the input parameter is User ID, and returns a one item as array of addresses:
getUserAddresses(user_id: string): Observable<Address[]>
[
{
"id": 1,
"city": "London",
"street": "Wicombe 34"
},
{
"id": 2,
"city": "Paris",
"street": "La fever 20"
},
...
]
3rd observable can be used to fetch companies assigned to user, so the input parameter is User ID, and returns a one item as array of companies:
getUserCompanies(user_id: string): Observable<Company[]>
[
{
"id": 1,
"name": "Fintch CO",
"state": "France"
},
{
"id": 2,
"name": "C&C inc.",
"state": "USA"
},
...
]
I want to chain these 3 observables into one which will produce the result again as one item, that will contain array of users with their additional addresses arrays and companies array, like following:
[
{
"id": 1,
"name": "Peter",
"surname": "Smith",
"addreesses":
[
{
"id": "1",
"city": "London",
"street": "Wicombe 34"
},
{
"id": "2",
"city": "",
"street": "La fever 20"
}
],
"companies":
[
{
"id": "1",
"name": "Fintch CO",
"state": "France"
},
{
"id": "2",
"name": "C&C inc.",
"state": "USA"
}
]
}
},
{
"id": 2,
"name": "John",
"surname": "Wayne",
"addresses": [...],
"companies": [...],
},
...
]
How should look like the operators composite to achieve that in Angular 6 with RxJs 6? Thanks a lot for advice.
Using pipe to combine operators The pipe method accepts operators such as filter , map , as arguments. Each argument must be separated by a comma. The order of the operators is important because when a user subscribes to an observable, the pipe executes the operators in a sequence in which they are added.
pipelink. pipe() can be called on one or more functions, each of which can take one argument ("UnaryFunction") and uses it to return a value. It returns a function that takes one argument, passes it to the first UnaryFunction, and then passes the result to the next one, passes that result to the next one, and so on.
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified. A Pipeable Operator is essentially a pure function which takes one Observable as input and generates another Observable as output.
Something like this could work
getUsers()
.pipe(
switchMap(users => from(users)),
mergeMap(user => forkJoin(getAddresses(user.id), getCompanies(user.id))
.pipe(map(data => ({user, addresses: data[0], companies: data[1] })))
tap(data => data.user.addresses = data.addresses),
tap(data => data.user.companies = data.companies),
map(data => data.user),
toArray()
)
)
Applied to a different use case a similar chain is explained in more details here.
To chain observables, you can use the flatMap
function. This function is like promises then, meaning the function is only executed once the observable has resolved to a value.
There is also an observable function called forkJoin
which allows you to wait for multiple async requests to all have resolved to a value.
Example:
getUsers().flatMap((users) => {
// the users variable is the list of users
var multipleObservables = [];
users.forEach((u) => {
multipleObservables.push(
getUserAddresses(u.id).map((usersAddresses) => {
u.addresses = usersAddresses;
return u;
});
);
});
return forkJoin(multipleObservables);
}).flatMap((usersWithAddresses) => {
// the usersWithAddresses variable is an array of users which also have their addresses
var multipleObservables = [];
usersWithAddresses.forEach((u) => {
multipleObservables.push(
getUserCompanies(u.id).map((usersCompanies) => {
u.companies = usersCompanies;
return u;
});
);
});
return forkJoin(multipleObservables);
});
You can write something like this to chain you request and grow your user objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With