0

I'm writing a library that adds validation to all routes, for use with koa-router.

In my routes/index.js file, before running any routes, I'm able to get most of what I want to achieve by using the following code:

    let routePath = ctx._matchedRoute as string;

    if (!routePath) {
        return next();
    }

    // Strip trailing slash and replace colon with underscore
    let routeName = routePath.replace(/\/$/, "").replace(/:/g, "_");
    let schemaName = `/requests/${ctx.method}${routeName}.json`;

    if (!hasSchema(schemaName)) {
        return next();
    }

    try {
        await validate(schemaName, {
            query: ctx.query,
            params: ctx.params,
            body: ctx.request.body,
            headers: ctx.headers
        });

        return next();
    } catch (err) {
        throw err;
    }

Unfortunately, ctx.params seems to be only populated "downstream", so at the level of the to-be-executed route handler. I'd like to get access to these parameters without having to define my middleware before each and every route handler. Is there a way to achieve this?

Ruben Rutten
  • 1,659
  • 2
  • 15
  • 30

1 Answers1

0

You basically have 2 options:

  1. Use the same libraries koa-route uses to parse the route and extract these parameters from urls.
  2. Wrap koa-route with your own middleware, so you have the possibility to be the first middleware that's being called after koa-route, and then call the regular post-routing middleware.

Both I think are valid options. If performance very important, you probably get a bit more about of option 2, as you don't need to parse the routes twice.

Evert
  • 93,428
  • 18
  • 118
  • 189
  • I was thinking of writing my own Router class, that does nothing more than basically adding my middleware before the `arguments` passed to it. I wasn't sure if there was a better way – Ruben Rutten Apr 19 '20 at 19:24
  • @RubenRutten koa middlewares are just simple functions. Koa-router is just a middleware, that will optionally call other middlewares. In a koa-world it makes sense to not provide a fancy API for this sort of thing, given that all the primitives are there to easily handle this. A class is probably overkill unless you actually need state. – Evert Apr 19 '20 at 19:29
  • Ill add a little example to this answer that demonstrates this. – Evert Apr 19 '20 at 19:32
  • The reason I'd want to write a class is so I can provide a drop-in replacement for all my current routers. Replacing `import * as Router from "koa-router";` by `import Router from "./my-own-router";`, providing the same API, only wrapping the original router and adding my middleware to the chain. – Ruben Rutten Apr 19 '20 at 19:33
  • I see, you're not using the official koa router. Looks like a class might be the way to go then. – Evert Apr 19 '20 at 19:34
  • I now see that `koa-router` is incredibly inactive and `@koa/router` is a fork that is actually maintained. I'll see if I can make the switch and how that'll affect what I'm trying to achieve – Ruben Rutten Apr 19 '20 at 19:37