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

Support multiple hosts for routing without use of RegExp #164

Open
2 tasks done
EdanKriss opened this issue Apr 9, 2023 · 0 comments
Open
2 tasks done

Support multiple hosts for routing without use of RegExp #164

EdanKriss opened this issue Apr 9, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@EdanKriss
Copy link

EdanKriss commented Apr 9, 2023

I use Koa @koa/router to serve multiple routers from the same webserver.
Each router serves one or more domains, sometimes including specific subdomains.

My suggestion is to enhance the type signature of Router.RouterOptions["host"] to support an array of strings, matched by equality to any member, in addition to the current single string equality and RegExp test.

I suppose the source code change would look like this: (line 771 in /lib/router.js)

Router.prototype.matchHost = function (input) {
  const { host } = this;

  if (!host) {
    return true;
  }

  if (!input) {
    return false;
  }

  if (typeof host === 'string') {
    return input === host;
  }

  if (typeof host === 'object' && host instanceof RegExp) {
    return host.test(input);
  }

+  if (Array.isArray(host)) {
+    return host.includes(input);
+  }
};

With the proposed change, the 'parent' koa app would only have the responsibility of providing an array of valid domains:

const router = new Router({
    host: [ 
        'some-domain.com',
        'www.some-domain.com',
        'some.other-domain.com',
    ],
});

I can currently accomplish similar results 2 separate ways, neither of which is as simple as I would like:

Workaround 1.

Build a dynamic RegExp from config at runtime, and assign to Router.RouterOptions["host"]
- requires escaping period characters from domain
- The ECMA proposal to ease this is still in infancy: https://github.com/tc39/proposal-regex-escaping
- cumbersome to handle subdomains without using wildcards or accidental performance pitfall
- pseudo example of my usage:

const domains = [ 
        'some-domain.com',
        'www.some-domain.com',
        'some.other-domain.com',
];
const router = new Router({
    host: new RegExp(`^(?:${domains.map(escapePeriods).join('|')})$`),
});

Workaround 2.

Execute router middleware conditionally, only if domain matches manual check
- Described generically here: https://github.com/koajs/examples/blob/master/conditional-middleware/app.js
- here is pseudo example of my usage:

constructor() {
    this.#examplePortalRoutes = examplePortalRouter.routes();
    this.#examplePortalAllowedMethods = examplePortalRouter.allowedMethods({ throw: true });
    this.#app.use(this.#catchErrors);
    this.#app.use(this.#domainLookup);
    this.#app.use<DomainConfigState>(this.#appRouter);
}

#domainLookup: Koa.Middleware<SettableDomainConfigState> = async (ctx, next) => {
    const domainConfig: DomainConfig | undefined = this.#domainConfigMap.get(ctx.request.hostname);
    if (domainConfig) {
        ctx.state.domainConfig = domainConfig;
        await next();
    } else {
        throw { message: `Unrecognized domain: ${domain}`, status: 400 } satisfies Errors.InvalidRequest;
    }
}

#appRouter: Koa.Middleware<DomainConfigState, Router.RouterParamContext> = async (ctx, next) => {
    switch (ctx.state.domainConfig.domainApp) {
        case 'example_portal':
            await this.#examplePortalRoutes.call(this, ctx, async () => {
                await this.#examplePortalAllowedMethods.call(this, ctx, next);
            });
            break;
    
        default:
            await next();
            break;
    }
}

Checklist

  • I have searched through GitHub issues for similar issues.
  • I have completely read through the README and documentation.
@EdanKriss EdanKriss added the enhancement New feature or request label Apr 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant