Search code examples
javascriptreactjsrxjsobservablerxjs6

How to make multiple HTTP requests with RxJS and merge the response into one payload and map it to another action?


As per the title, I've been trying to figure out a way to make multiple HTTP calls from an action payload and basically merging all results into a single array and then map the result to another action as a payload.

Here is my existing code, it works but it seems it seem not merging both responses and only cares about last response from the request's response, perhaps I'm using the wrong operator, I'm just picking up RxJS and trying different things to learn, hopefully somebody is able to explain where I'm going wrong.

Any help or direction is much appreciated.


{
    type: 'FETCH_DATA',
    payload: {
        key: 'standings',
        value: [
                'http://url-1',
                'http://url-2'
        ],
    })
}


// The epic is listening to the above action

const fetchDataEpic = action$ => action$.pipe(
    ofType('FETCH_DATA'),
    mergeMap(action => {
        const { key, value } = action.payload;
        if (Array.isArray(value) && value.length) {
            const makeRequest = value.map((x, i) => ajax.getJSON(value[i]))

            return (
                forkJoin(
                    makeRequest,
                    response => {
                        return ({
                            type: 'FETCH_DATA_SUCCEEDED',
                            payload: {
                                key,
                                value: response,
                            },
                        })
                    }
                )
            )
        }
    })
);

NOTE: Both request's response is in same JSON format with same properties, but different data.

Thanks in advance


Solution

  • I don't think it only cares about the last response, but the first one.

    That's because if you want to customize the response from forkJoin, the second(or last, in case the first one isn't an array) argument(which is a function) accepts multiple arguments, which are the responses from the supplied requests.

    Thus, this is the change I'd perform in order to get the whole array of responses.

    /* ... */
    forkJoin(
        makeRequest,
        (...response) => {
            return ({
                type: 'FETCH_DATA_SUCCEEDED',
                payload: {
                    key,
                    value: response,
                },
            })
        }
    )
    /* 
    

    Edit: sending the merged responses to another action

    This can be achieved by using the tap operator, which is commonly used when you have to deal with side effects.

    (
     mergeMap(action => { ... }),
     tap(action => sendToOtherAction(action))
    )