Firstly, I think I need to know if my approach is bad or not. I'm trying to allow a user to upload an image and register their profile on one button press. This means two http requests, one to upload the image to s3 (with a random uuid) and afterwards, use the same uuid and the signed url from the previous request to create a user in my dynamo db with the same uuid as the userid and an image field to contain the s3 url.
I could be just overcomplicating things, but I'm learning so much about rxjs and ngrx so I think I'll continue torturing myself.
This is the effect I've cooked up so far:
export const uploadEffect = createEffect(
(action$ = inject(Actions), authService = inject(AuthService)) => {
return action$.pipe(
ofType(AuthActions.upload),
concatMap(({ uploadRequest }) => {
return authService.uploadImage(uploadRequest).pipe(
map((uploadSuccess) => {
return AuthActions.uploadSuccess({ uploadSuccess });
}),
catchError((error: ServerError) => {
return of(AuthActions.uploadFailure({ error }));
})
);
}),
switchMap((action) => {
if (action.type === '[Auth API] Upload Success') {
return authService
.registerUser({
user: {
...action.uploadSuccess,
image: action.uploadSuccess.url,
},
})
.pipe(
map((response: RegisterResponseInterface) => {
return AuthActions.registerSuccess({
message: response.message,
});
}),
catchError((error: ServerError) => {
return of(
AuthActions.registerFailure({
error,
})
);
})
);
} else if (action.type === '[Auth API] Upload Failure') {
return of(
AuthActions.registerFailure({
error: {
message: 'failed to upload and register',
},
})
);
} else {
return EMPTY;
}
})
);
},
{
functional: true,
}
);
It's my attempt to upload first and then if successful, make another request to register a user. The problem with this approach is that since I'm just calling one dispatch (AuthActions.upload), I have to send password and email and user info into a nest controller that only deals with s3 uploads.
To my knowledge, this is the only way to dispatch one action with two requests (use the response from the first request in the second)
Like I said, this could just be bad practice but I'm not deploying it or anything just trying to learn rxjs and ngrx better.
Here are both my effects if it'll help clarify anything:
Register effect:
export const registerEffect = createEffect(
(action$ = inject(Actions), authService = inject(AuthService)) => {
return action$.pipe(
ofType(AuthActions.register),
switchMap(({ request }) => {
return authService.registerUser(request).pipe(
map((response: RegisterResponseInterface) => {
return AuthActions.registerSuccess({ message: response.message });
}),
catchError((error: ServerError) => {
return of(
AuthActions.registerFailure({
error,
})
);
})
);
})
);
},
{ functional: true }
);
Upload effect without the register effect added to it:
export const uploadEffect = createEffect(
(action$ = inject(Actions), authService = inject(AuthService)) => {
return action$.pipe(
ofType(AuthActions.upload),
switchMap(({ uploadRequest }) => {
return authService.uploadImage(uploadRequest).pipe(
map((uploadSuccess) => {
return AuthActions.uploadSuccess({ uploadSuccess });
}),
catchError((error: ServerError) => {
return of(AuthActions.uploadFailure({ error }));
})
);
})
);
},
{
functional: true,
}
);