I've got a very bizarre issue with this epic. It's working fine on desktop, android but not working at all on iOS.. well it never picks up the action. I'm sure the action is being fired (but I've not got redux dev tools remote to work yet to confirm)
export function authenticate(action$) {
return action$.ofType(USER_LOGIN)
.mergeMap(({email, password}) => login(email, password)
.map(res => {
console.log(res)
if (res.error) {
return { type: AUTH_FAILED, payload: res.message }
} else {
return { type: AUTH_SUCCESS, payload: res.payload }
}
})
.catch(err => {
console.log('Login error: ', err)
return { type: AUTH_FAILED, message: err }
})
)
}
The action is being fired in
function selectorFactory(dispatch) {
return state => ({
...
login: (email,password) => dispatch(userLogin(email,password)),
...
}
I've console logged this as working, we're getting to the dispatch, but that epic is not firing.. any clues?
Caused by an error elsewhere that was very hard to debug.
Related
I am getting an error when I request. Оn the backend side there is a check that the name length is at least 3 characters. The response from the server is correct. but when I try to display an error, the message comes out saying that the answer was not found.
async saveBoard(id, index) {
await this.API.put("/boards/" + id, {
name: this.boards[index].name,
})
.then((response) => {
alert(response.data.message);
this.boards[index].etitable = !this.boards[index].etitable;
})
.catch((error) => {
console.log(error);
});
},
when I try to output error.response.date to the console, I get an error that response is not defined.
How can I solve this problem, why does axios not see the response from the server and the error code?
Error code must be in your catch You can't reach error message in then.
You are probably see error in your console right now
return response;
},
error => {
if (error.response.status == 401 || error.response.status == 419) {
const token = localStorage.getItem('token');
if (token) {
localStorage.removeItem('token');
}
const user = localStorage.getItem('user');
if (user) {
localStorage.removeItem('user');
}
router.push('/login');
} else {
if (error.response.status == 403) {
router.push('/');
}
}
return Promise.reject(error);
});```
I added a return to the interceptors function. Problem solved thanks for your help.
I am facing a timeout issue with nestJs Httpservice.
The error number is -60 and error code is 'ETIMEDOUT'.
I am basically trying to call one api after the previous one is successfully.
Here is the first api
getUaaToken(): Observable<any> {
//uaaUrlForClient is defined
return this.httpService
.post(
uaaUrlForClient,
{ withCredentials: true },
{
auth: {
username: this.configService.get('AUTH_USERNAME'),
password: this.configService.get('AUTH_PASSWORD'),
},
},
)
.pipe(
map((axiosResponse: AxiosResponse) => {
console.log(axiosResponse);
return this.getJwtToken(axiosResponse.data.access_token).subscribe();
}),
catchError((err) => {
throw new UnauthorizedException('failed to login to uaa');
}),
);
}
Here is the second api
getJwtToken(uaaToken: string): Observable<any> {
console.log('inside jwt method', uaaToken);
const jwtSignInUrl = `${awsBaseUrl}/api/v1/auth`;
return this.httpService
.post(
jwtSignInUrl,
{ token: uaaToken },
{
headers: {
'Access-Control-Allow-Origin': '*',
'Content-type': 'Application/json',
},
},
)
.pipe(
map((axiosResponse: AxiosResponse) => {
console.log('SUCUSUCSCUSS', axiosResponse);
return axiosResponse.data;
}),
catchError((err) => {
console.log('ERRRORRRORROR', err);
// return err;
throw new UnauthorizedException('failed to login for');
}),
);
}
Both files are in the same service file. Strangely, when i call the second api through the controller like below. It works fine
#Post('/signin')
#Grafana('Get JWT', '[POST] /v1/api/auth')
signin(#Body() tokenBody: { token: string }) {
return this.authService.getJwtToken(tokenBody.token);
}
When the two api's are called, however, the first one works, the second one that is chained is giving me the timeout issue.
Any ideas?
Two things that made it work: changed the http proxy settings and used switchMap.
I have a async problem with my Vuejs/Laravel App.
If a user is connected i have in vuex : my state user and a state token. I set this token in the localStorage and with that i can relogin him if my user F5 (refresh page).
There is my store (namespaced:auth) :
export default {
namespaced: true,
state: {
token: null,
user: null
},
getters: {
authenticated(state){
return state.token && state.user;
},
user(state){
return state.user;
}
},
mutations: {
SET_TOKEN(state, token){
state.token = token;
},
SET_USER(state, data){
state.user = data;
},
},
actions: {
async login({ dispatch }, credentials){
let response = await axios.post(`/api/auth/connexion`, credentials);
dispatch('attempt', response.data.token);
}
,
async attempt({ commit, state }, token) {
if(token){
commit('SET_TOKEN', token);
}
if (!state.token){
return
}
try{
let response = await axios.get(`/api/auth/me`);
commit('SET_USER', response.data);
console.log('Done')
}
catch(err){
commit('SET_TOKEN', null);
commit('SET_USER', null);
}
}
}
}
My app.js, i do that for relog my current user :
store.dispatch('auth/attempt', localStorage.getItem('token'));
And for finish on route in router :
{
name: 'Login',
path: '/',
component: Login,
beforeEnter: (to, from, next) => {
console.log('Getter in router : ' + store.getters['auth/authenticated']);
if (!store.getters['auth/authenticated']){
next()
}else {
return next({
name: 'Home'
})
}
}
}
Where is the problem, if i call in a Home.vue my getter "authenticated" is work fine (true if user connect and false if not).
But in my router is take all time default value set in store (null). I know why is because if i reload my page for 0.5s the store state is null and after that the localStorage is learn and my user and token is created.
What i want (i think) is the router wait my actions attempt and after that he can do check.
I have follow a tutoriel https://www.youtube.com/watch?v=1YGWP-mj6nQ&list=PLfdtiltiRHWF1jqLcNO_2jWJXj9RuSDvY&index=6
And i really don't know what i need to do for my router work fine =(
Thanks a lot if someone can explain me that !
Update :
If i do that is work :
{
name: 'Login',
path: '/',
component: Login,
beforeEnter:async (to, from, next) => {
await store.dispatch('auth/attempt', localStorage.getItem('token'));
if (!store.getters['auth/authenticated']){
next()
}else {
return next({
name: 'Home'
})
}
}
But i want to understand what i really need to do because that is not a clear way is really trash.
Update2:
Maybe i found the best solution if someone have other way i take it.
{
name: 'Home',
path: '/accueil',
component: Home,
beforeEnter: (to, from, next) => {
store.dispatch('auth/attempt', localStorage.getItem('token')).then((response) => {
if (!store.getters['auth/authenticated']){
return next({
name: 'Login'
})
}else {
next();
}
});
}
}
I answer more clearly how easily wait the store !
Before in my app.js i have this :
store.dispatch('auth/attempt', localStorage.getItem('token'));
Is set for normaly every reload do that but if i put a console.log in, i see the router is execute and after the action 'attempt' is execute.
So delete this line in app.js and you can add a .then() after !
router.beforeEach((to, from, next) => {
store.dispatch('auth/attempt', localStorage.getItem('token')).then(() =>{
if (store.getters['auth/authenticated']){
next();
}else {
//something other
}
})
})
With that i have the same line code but i can say wait action "attempt" to my router.
I'm not sur is the best way obviously. But is work and i think is not a bad way !
EDIT
I boiled down the problem. The following code yields an error in tests, but works as expected in the browser (see https://github.com/prumand/jest-marbles-merge-map and https://github.com/ReactiveX/rxjs/issues/4837)
tests: returns a WE_FINISH
browser (expected): MY_NEW_ERROR
// code
export default function basicMergeMapObs(
action$: Observable<Action>
) : Observable<any> {
return action$.pipe(
filter((val: Action) => {
throw new Error('We stop here')
}),
map((val: Action) => ({
type: 'WE_FINISH',
})),
catchError(() => of({
type: 'MY_NEW_ERROR',
}))
)
}
// test
it('should yield an MY_ERROR', () => {
const source = of({
type: 'TEST',
status: 'NEW'
})
getScheduler().run(helpers => {
const { expectObservable, cold } = helpers
expectObservable(
basicMergeMapObs(
source
)
).toBe(
'(t|)',
{
t: { type: 'MY_NEW_ERROR' }
}
)
})
})
function getScheduler() {
return new TestScheduler((actual, expected) => {
expect(actual).toMatchObject(expected);
});
}
UPDATE 19.06.2019
I added cartants example from the given github issue, which works fine. Still my example fails. No idea why. IMO it should always throw an error.
And yet another update, the tests don't fail on linux, but only on my windows machine
UPDATE 02.07.2019
:O seemed to be a issue with endpoint-security solution we use ...
I have SPA application on Vue.js + Laravel. Authorization logic, completely delegated to Laravel app. However, i need check auth status, when routing has changed. I create small class, which responsible for it.
export default {
user: {
authenticated : false
},
check: function(context) {
context.$http.get('/api/v1/user').then((response) => {
if (response.body.user != null) {
this.user.authenticated = true
}
}, (response) =>{
console.log(response)
});
}
Within the component has a method that is called when a change url.
beforeRouteEnter (to, from, next) {
next(vm =>{
Auth.check(vm);
if (!Auth.user.authenticated) {
next({path:'/login'});
}
})
}
Function next() given Vue app instance, then check user object. If user false, next() call again for redirect to login page. All it works, but only when the page is already loaded. If i'll reload /account page, there is a redirect to /login page, because request to Api not completed yet, but code will continue execute. Any idea?
Quite simple to do, you need to make your code work asynchronously and hold routing before request is completed.
export default {
user: {
authenticated : false
},
check: function(context) {
return context.$http.get('/api/v1/user').then((response) => {
if (response.body.user != null) {
this.user.authenticated = true
}
}, (response) => {
console.log(response)
});
}
}
then
beforeRouteEnter (to, from, next) {
next(vm => {
Auth.check(vm).then(() => {
if (!Auth.user.authenticated) {
next({path:'/login'});
} else {
next()
}
}
})
}
Other pro tips
Display some loading indicator when loading so your application doesn't seem to freeze (you can use global router hooks for that)
If you are using vue-resource, consider using interceptors (perhaps in addition to the routing checks)
Consider using router.beforeEach so that you don't have to copy-paste beforeRouteEnter to every component
Done. Need to return promise like that
check: function(context) {
return context.$http.get('/api/v1/user').then((response) => {
if (response.body.user != null) {
this.user.authenticated = true
}
}, (response) =>{
console.log(response)
});
}
and then
beforeRouteEnter (to, from, next) {
Auth.check().then(()=>{
if(!Auth.user.authenticated)
next({path:'/login'})
else
next();
})
}