berstend / service-worker-router

➰ An elegant and fast URL router for service workers (and standalone use)
94 stars 6 forks source link

Multiple Routers #6

Closed sbwrege2z closed 4 years ago

sbwrege2z commented 4 years ago

I am having a problem with multiple routers. I have a main router and a redirect router. The main router simply looks for the presence of an old ".aspx" extension and it's handler calls the redirect module's handler which has it's own router and route definitions. That way I don't have to load up the main route table with a bunch of redirects routes that will get hit less and less over time.

The problem I am having is the main router's handlerPromise seems to resolve immediately, As soon as the secondary router's handler does an async operation, the main router's handler takes back over with a resolved promise.

The main router has this route defined:

router.get('*.aspx', redirects.handleRedirect);

And here is the redirect's handleRedirect function:

async function handleRedirect({ event, request, url, method }) {
  if (event) return redirectRouter.handleEvent(event);
  if (request) return redirectRouter.handleRequest(request);
  return redirectRouter.handle(url, method);
}

The instant the redirectRouter's handler performs an asynchronous operation, the handlerPromise from the main router is resolved. Ideally I'd like to wait until the redirectRouter's handlerPromise is resolved. I thought this would be solved by returning the redirectRouter's handle event, but it doesn't seem to be.

I'm sure this is an issue in my coding, but I was hoping you could give me some insights in the possibility of using multiple routers. I can always define the redirectRouters routes on the main router and everything seems to work fine. I just like the idea of this kind of indirection when 20 or 30 routes will decay over time and shouldn't need to be checked with every request.

Thanks for any help.

Best Regards, Shannon

sbwrege2z commented 4 years ago

Providing a little more detail. This single router approach will work:

SINGLE ROUTER (router.js)

  const UrlPattern = require('url-pattern');
  const { Router } = require('service-worker-router');
  const router = new Router();

  // Normal Routes:
  // ...

  // Redirect Routes:
  router.get(new UrlPattern(/^\/foo\/(.*?).aspx$/), fooModule.redirect);
  router.get(new UrlPattern(/^\/bar\/(.*?).aspx$/), barModule.redirect);
  // ... ~30 more specific routes
  router.get('*.aspx', aspModule.redirect);

  // Wildcards:
  router.get('*', defaultHandler);
  router.post('*', methodNotAllowed);
  router.put('*', methodNotAllowed);
  router.patch('*', methodNotAllowed);
  router.delete('*', methodNotAllowed);

But this dual router approach with one level of indirection does not:

MAIN ROUTER (router.js)

  const { Router } = require('service-worker-router');
  const router = new Router();

  // Normal Routes:
  // ...

  // Redirect Routes:
  router.get('*.aspx', redirects.handleRedirect);

  // Wildcards:
  router.get('*', defaultHandler);
  router.post('*', methodNotAllowed);
  router.put('*', methodNotAllowed);
  router.patch('*', methodNotAllowed);
  router.delete('*', methodNotAllowed);

REDIRECT ROUTER (redirects.js)

   const UrlPattern = require('url-pattern');
   const { Router } = require('service-worker-router');
   const router = new Router();

  router.get(new UrlPattern(/^\/foo\/(.*?).aspx$/), fooModule.redirect);
  router.get(new UrlPattern(/^\/bar\/(.*?).aspx$/), barModule.redirect);
  // ... ~30 more specific routes
  router.get('*.aspx', aspModule.redirect);

  async function handleRedirect({ event, request, url, method }) {
    if (event) return router.handleEvent(event);
    if (request) return router.handleRequest(request);
    return router.handle(url, method);
  }

As soon as the fooModule.redirect, barModule.redirect, or aspModule.redirect do anything asynchronous, the main router's handlerPromise resolves in the dual router approach (my bug), but not in the first single router approach where things are working but a bunch of additional routes must get checked on each request.

sbwrege2z commented 4 years ago

I solved the problem. I actually needed to return the secondary promises' result in the main router's handler:

async function handleRedirect({ event, request, url, method }) {
  if (event) return router.handleEvent(event).handlerPromise;
  else if (request) return router.handleRequest(request).handlerPromise;
  return router.handle(url, method).handlerPromise;
}