svelte-router
svelte-router copied to clipboard
Async route guarding?
Thanks for the great package! I was wondering if it's currently possible to guard a route using an asynchronous function. It doesn't seem to work with the implementation I have in the example below but I wasn't sure if I was just doing something wrong:
#routes.js
# Check user consent status using a call to google firebase
async function checkConsent() {
try {
let resp = await db.collection('users').doc('test-user').get();
let consent = resp.data().consent;
return consent ? true : false;
} catch (error) {
console.error(error);
}
}
# Render the instructions route depending on the consent status of the user
export const routes = [
{
name: 'instructions',
component: Instructions,
onlyIf: { guard: checkConsent, redirect: '/exitSurvey' }
}
]
Hello @ejolly
Async functions are not supported now. But I'll add that to the TODO list. I'll let you know once it's implemented.
Hello @ejolly
Async functions are not supported now. But I'll add that to the TODO list. I'll let you know once it's implemented.
are pull requests welcomed?
Of course @pckkkkkk
They are more than welcome.
[ EDIT ] THE WORKAROUND BELOW DOES NOT WORK. The isConsented() function returns always false because the IIFE pattern immediately returns a PENDING promise :( I think there is no way to bypass the problem excepted modifying the way the router handle the guard function to accept promises as returned results.
Hi @ejolly
I faced this problem too.
As a workaround I used the IIFE pattern (Immediatly Invoked Function Execution).
Here is an implementation example.
Hope it'll help ;)
// Check user consent status using a call to google firebase
async function checkConsent() {
try {
let resp = await db.collection('users').doc('test-user').get();
let consent = resp.data().consent;
return consent ? true : false;
} catch (error) {
console.error(error);
}
}
// This function will wait for the promise resolution
// (or rejection) of your async function before returning.
function isConsented() {
let consent false;
// IIFE pattern is here
(async function() {
consent = await checkConsent(); // (if you prefer, you can also directly include the content of your checkConsent() function here)
})();
// The line below will be executed once the promise
// returned by the checkConsent() function will be resolved.
return consent;
}
// Render the instructions route depending on the consent status of the user
export const routes = [
{
name: 'instructions',
component: Instructions,
onlyIf: { guard: isConsented, redirect: '/exitSurvey' }
}
]
In the same vein, it would probably be a good idea to have async component resolution for code splitting.
Hi @jorgegorka, First of all, best wishes for 2021 ! ;) I was wondering if the status of this enhancement request evolved since last year ? Regards
Hi @jorgegorka, any plans to implement this enhancement yet?
@moalamri If @jorgegorka ok with it, i can implement this feature
@si3nloong you have done great work for this awesome library. I'm sure @jorgegorka is totally open for PRs as he mentioned above. This will be an awesome addition, so thank you in advance.
@si3nloong also i want to mention that I've tried to implement this, but I was uncertain about either I make a new method where it is called guardAsync or make the existing method as a promise, because trying to implement a method to detect the function type is not a good practice, so making it as a promise for all seems to be the best approach.
Anyways eventually I didn't do anything, but I'm putting hope on you :)
solution for firebase
routes.js
import { auth } from './firebase';
function userIsAuthenticated() { let user = auth.currentUser; if (!user) { return false; } else return true; }
const routes = [ ... { name: 'xxx', component: XXX, onlyIf: { guard: userIsAuthenticated, redirect: 'login' }, }, ... ]
Any updates on this? It's been open for quite a while. Or any suggestions for a workaround, because I need to fetch from the server to know about a guard.
@stemaDev I ended up fetching allowed components names from the database after a successful login. Then dynamically load the allowed components.
After the login I redirected to a guarded page, I wanted that to double check from the server, but instead I am setting a cookie on the server and checking that in the guard method. So it's a similar workaround as your. Thanks for thq quick answer btw.
I think we both have different approach :) Perhaps if you followed mine it would be better and I will explain why. But I need you to elaborate for me... If by cookie you mean jwt payload?