My use case is:
- User requests asset from our API which fails because of JWT expiring (passed as an httpOnly cookie) - API returns a 401 status code.
- We go and authenticate them (without the user doing anything) again using a refresh_token to retrieve a new JWT with a request from our client to auth0.
- We send that new JWT to our API to be set as an httpOnly cookie to replace the expired one.
- We then want to retry the original request the user made to the API in step 1.
I'm trying to use Observables within my Redux app with redux-observable. If you can think of another way of making the above user flow work I would be happy to hear how.
NB. Im using rxjs V5
export const fetchAssetListEpic = (action$, store) => {
return action$.ofType('FETCH_ASSET_LIST')
.switchMap( action => {
const options = {
crossDomain: true,
withCredentials: true,
url: uriGenerator('assetList', action.payload)
};
return ajax(options);
})
.map(fetchAssetListSuccess)
.retryWhen(handleError)
.catch(redirectToSignIn);
};
function handleError(err) {
return (err.status === 401) ?
/* Authenticate here [Step 2] */
/* Send new JWT to API [Step 3] */
/* If successful make original request again [Step 4] */
:
Observable.throw(err);
}
function redirectToSignIn() {
/*I will redirect here*/
}
My use case is:
- User requests asset from our API which fails because of JWT expiring (passed as an httpOnly cookie) - API returns a 401 status code.
- We go and authenticate them (without the user doing anything) again using a refresh_token to retrieve a new JWT with a request from our client to auth0.
- We send that new JWT to our API to be set as an httpOnly cookie to replace the expired one.
- We then want to retry the original request the user made to the API in step 1.
I'm trying to use Observables within my Redux app with redux-observable. If you can think of another way of making the above user flow work I would be happy to hear how.
NB. Im using rxjs V5
export const fetchAssetListEpic = (action$, store) => {
return action$.ofType('FETCH_ASSET_LIST')
.switchMap( action => {
const options = {
crossDomain: true,
withCredentials: true,
url: uriGenerator('assetList', action.payload)
};
return ajax(options);
})
.map(fetchAssetListSuccess)
.retryWhen(handleError)
.catch(redirectToSignIn);
};
function handleError(err) {
return (err.status === 401) ?
/* Authenticate here [Step 2] */
/* Send new JWT to API [Step 3] */
/* If successful make original request again [Step 4] */
:
Observable.throw(err);
}
function redirectToSignIn() {
/*I will redirect here*/
}
So far I able to plete steps 1, 2 and 3 but not too sure of a way to add step 4. I may be pletely off the mark but any help would be great!
Share Improve this question asked Dec 1, 2016 at 9:23 JbargetJbarget 5691 gold badge5 silver badges15 bronze badges1 Answer
Reset to default 8Well one thing you probably won't want to do is allow the error to make it to the top level stream. Even if you do a catch
you have effectively killed the top level stream. So unless your redirect is doing a hard redirect instead of a a soft one via something like react-router, you won't be able to use this epic any more.
Thus I would say that you want most of the logic to be encapsulated within the switchMap
:
function withAuthorizedFlow(source) {
return source
.map(fetchAssetListSuccess)
// retryWhen takes a callback which accepts an Observable of errors
// emitting a next causes a retry, while an error or plete will
// stop retrying
.retryWhen(e => e.flatMap(err =>
Observable.if(
// Returns the first stream if true, second if false
() => err.status === 401,
reauthenticate, // A stream that will emit once authenticated
Observable.throw(err) // Rethrow the error
))
)
.catch(redirectToSignIn);
}
/** Within the epic **/
.switchMap(({payload}) => {
const options = {
crossDomain: true,
withCredentials: true,
url: uriGenerator('assetList', payload)
};
// Invoke the ajax request
return ajax(options)
// Attach a custom pipeline here
// Not strictly necessary but it keeps this method clean looking.
.let(withAuthorizedFlow);
})
The use of let
above is pletely optional, I threw it in to clean up the function. Essentially though you want to contain the error to the inner stream so that it can't halt the outer one. I am not sure which ajax
library you are using but you should also confirm that it will in fact return a cold Observable
otherwise you will need to wrap it in a defer
block to in order for the retryWhen
to work.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744839864a4596492.html
评论列表(0条)