Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass response logic to children routes #74

Closed
mparker11 opened this issue May 22, 2018 · 4 comments
Closed

Pass response logic to children routes #74

mparker11 opened this issue May 22, 2018 · 4 comments

Comments

@mparker11
Copy link

Is there a way to pass response logic to children routes? The use case is I have one parent route then a bunch of children routes, say like:

album
album/1
album/2
album/3
album/etc

So I would like to block access to album and all its children. The problem is, it seems the best I can do create a function and pass it to every child. However, I'm looking to only write and use a piece a logic once in the parent. Any ideas? Thanks.

@pshrmn
Copy link
Owner

pshrmn commented May 23, 2018

I'm not exactly certain what you're trying to do. Maybe if you show me what you're doing right now, it will be more clear. Even some pseudo code of what you would like might help.

@mparker11
Copy link
Author

Sure thing. So I have something like this:

{ 
    name: 'Dashboard', 
    path: 'dashboard',
    response: () => {
        if (isLoggedIn)) {
            return {
                body: Dashboard,
            }
        } else {
            return {
                redirectTo: { name: 'Login' }
            }
        }
    },
    children: [
        { 
            name: 'Community', 
            path: 'community',
            response: () => {
                return {
                    body: Community
                }
            }
        },
    ]
}

So whenever I hit /dashboard/community, I would like Community to only be hit if the user is logged in, per the Dashboard logic. Since I placed the logged in logic on the parent, is there a way already built that allows every child route to use the same isLoggedIn logic without duplicating code (or creating a global function)?

@pshrmn
Copy link
Owner

pshrmn commented May 23, 2018

Okay, now we're on the same page. I'll look into what other routers/web frameworks do with this.

  • Django uses view decorators that automatically redirect when the user isn't logged in.
  • Ruby on Rails might do some conditional checking prior to matching routes (i.e. only check some routes when the user isn't logged in). I've never used RoR, so I will have to do some more research.
  • With Express (Node), you would add middleware to automatically redirect when the user isn't logged in.

These two strategies can be distinguished by when they do the authentication check.

  1. Match a route, then check if the user is authenticated (Django and Express)
  2. Limit the routes that can be checked based on some condition (e.g. authentication) (RoR).

In theory, routes could have a check that would prevent their children from attempting to match against a location. For example, an on.match() function could return a boolean to indicate whether it (and its children?) are allowed to match. While this could work, I have a few alarm bells running in my head already about issues this might cause, so I'm not crazy about it.

{ 
    name: 'Dashboard', 
    path: 'dashboard',
    on: {
      match: () => {
        // when the user is not logged in, this will return false
        // and the router will skip this tree
        return isLoggedIn;
      }
    },
    response: () => {
        return {
          body: Dashboard,
        }
    },
    children: [
        { 
            name: 'Community', 
            path: 'community',
            response: () => {
                return {
                    body: Community
                }
            }
        },
    ]
}

I think I would prefer just "protecting" each route with a shared function. This might be a little less convenient because you have to add it to every "protected" route, but it makes more sense to me and doesn't add any more complication to the router.

function protectedRoute(proceed) {
  return function(routeData) {
    if (!isLoggedIn) {
      return {
        redirectTo: {
          name: "Login",
          state: { next: routeData.match.location.pathname }
        }
      };
    }
    return proceed(matchData);
  }
}

const routes = [
  { 
    name: 'Dashboard', 
    path: 'dashboard',
    response: protectedRoute(() => {
      return {
          body: Dashboard,
      };
    },
    children: [
        { 
            name: 'Community', 
            path: 'community',
            response: protectedRoute(() => {
                return {
                    body: Community
                }
            })
        },
    ]
  }
]

@mparker11
Copy link
Author

Yeah I figured this might be the way to go. Thank you for confirming!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants