Adding middleware to routes defined within third party Adonis addons

As the Adonis community continues to grow I suspect the number of third party addons that are available will continue to grow as well. But sometimes it's helpful to make small changes to their default behavior that isn't clearly exposed in config.

Adding middleware to routes defined within third party Adonis addons

As the Adonis community continues to grow I suspect (and hope) the number of third party addons that are available will continue to grow as well.

It is possible (and some do) to define routes within addon code. In some cases you may want or need to add custom middleware to those routes.

One such add-on that does this is adonis-swagger which lets you define swagger docs inline as jsdoc comments. Pretty useful when building out an api to have the docs (or at least part of them) right there in the comments. Though if I'm honest, editing yaml in comments is kind of a pain.

Anyway, adonis-swagger provides a route /swagger.json that dynamically generates a swagger json swagger definition file on request.

I'm making use of this add-on on my current closed-source project, and the api I'm documenting will only be consumed by our detached front-end Vue app, so while having documentation is very important, I also want to lock it down to just internal users.

I have a flag on my user records indicating whether a user is internal or not, so I've created a custom middleware that checks for this or responds with a 403 code.

I also need to ensure that users have provided valid credentials, that's easily done with the built in basic auth method. Combining the two I can trigger a basic auth login window, and ensure that not only valid user credentials are passed, but that the user is flagged as being an internal user.

Unfortunately, that route is defined within the addon code, and ideally I shouldn't have to fork a third party addon just to make that sort of change.

And... surprise surprise, I don't have to.

The solution really couldn't be simpler. I simply need to pull the item from the defined routes, and manipulate it.

Route.match() allows that to be done easily.

What I ended up with is adding this in my start/routes.js file:

Route
  .match('/swagger.json', 'GET')
  .route
  .middleware(['auth:basic', 'isInternalUser'])

Route.match() finds the route definition that matches the supplied path and method, then .route gives you the same scope you get with all your other route definitions, so adding middleware works here just as it does if I were manually defining that route and pointing it at a controller method of my own.

I also did the same for the /docs route that generally gets handled by the public/docs/index.html file. Instead I created a /docs route with the same middleware as above, that returns a view that is basically just the same contents of that original index.html file, after moving that file out of the way my route takes over and serves up the same thing, but as a view.

The end result, I navigate to /docs (or /swagger.json) and am presented a basic auth login window. Signing in as my own internal user persona, I am greated with the swagger ui and my swagger docs. Supplying invalid credentials or a non-internal user's credentials I get an access denied 403 response.


Share Tweet Send
0 Comments