Currently, @ngrx/effects does not have any support for the correlation id pattern. It would be great if there were utilities that help streamline the code.
Inside our app, it's often necessary to dispatch an action, wait for another action in response and then continue with follow-up logic.
Example:
Because our app needs to rely on generic stores, it's not feasible to implement each flow with special actions which can be easily filtered for, so we have correlationIds. This is a known pattern, but we have to implement the things around it on our own.
It would be great if there utilities inside the @ngrx/effects package:
const myAction = {type: 'MY_ACTION'};
const actionWithCorrelationId = withCorrelationId(myAction);
// => {type: 'MY_ACTION', _ngrx_correlation_id: 'some correlation id'}
filterActionsWithCorrelationId(actionWithCorrelationId: {type: string; _ngrx_correlation_id: string}, actionTypesToWaitFor: string[]});
@Effect({withCorrelationId: true})
someEffect$ = this.actions$.pipe(
filter(action => action.type === 'SOME_ACTION'), // action has _ngrx_correlationId="abc" set
map(() => ({type: 'SOME_OUTGOING_ACTION'})) // outgoing action also has _ngrx_correlationId="abc" set
);
Alternatively, you could also decide to always add the correlationId, so there is no property required.
Edit: I'm not sure this is possible to implement, the effects library somehow has to know not only what comes out of the stream but also what goes into it.
@Effect()
doSth$ = this.actions$.pipe(
filter(action => action.type === 'ACTION_A'),
switchMap(() => {
const outgoingAction = withCorrelationId({type: 'SOME_ACTION'});
const responseAction$ = this.actions$.pipe(
filterActionsWithCorrelationId(outgoingAction, ['SOME_RESPONSE_ACTION']),
map(responseAction => {
// responseAction is SOME_RESPONSE_ACTION
})
);
return merge(of(outgoingAction), responseAction$));
})
);
@Effect({withCorrelationId: true})
someEffect$ = this.actions$.pipe(
filter(action => action.type === 'SOME_ACTION'),
map(() => ({type: 'SOME_RESPONSE_ACTION'}))
);
[x] Yes (Assistance is provided if you need help submitting a pull request)
[ ] No
Closing as we won't be adding this to effects
Why? IT IS Common usecase. You have it in NGRX/Data as well
@brandonroberts It would be nice to know if you would be adding this to a separate library? or what's the plan around it?
in my opinion, you should have been able to create this functionality with something like :
// custom action creator
createActionWithCorrelationId(...) { return createAction(.../add props and corrId/.. }
// custom effect creator
createCorrelatedEffect() { .. it has to take correlatino ID from input to observable stream and add it to output actions.. }
submitData$ = createCorrelatedEffect(() =>
this.actions$.pipe(
ofType(actionCreatedByActionWithCorrelationIDCreator),
....,
// effect has to take this output (wrap observable) and add correlation ID.
map(x=> OutputActionWithCorrelationId())
));
FWIW, I implemented correlation at ngrx-etc.
You can see if this fits your needs, be aware that this is untested code (that's why it isn't documented)
FWIW, I implemented correlation at ngrx-etc.
You can see if this fits your needs, be aware that this is untested code (that's why it isn't documented)
Unfortunately action created with this Is not handled correctly in standard effect :/ not catched.