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

Router middleware not used at all if no routes match #436

Open
KyleJune opened this issue Dec 12, 2021 · 1 comment
Open

Router middleware not used at all if no routes match #436

KyleJune opened this issue Dec 12, 2021 · 1 comment

Comments

@KyleJune
Copy link

In my actual application, I have a main router that the application uses, then a router for "/api". I tried adding error handling to the api router so that any invalid api paths will be handled with json response vs html for the main application error handler. I found that if I go to /api/invalid, the api middleware wouldn't be used, only the application middleware would be used.

I've reproduced the issue in the example below.

If I make a request to "/a", both routerA and routerB middleware is used since routerB doesn't specify a path.
If I make a request to "/d" which throws an error, it correctly uses the routers error handler.
If I make a request to "/c", it correctly uses the middleware and get handler for routerC.
If I make a request to "/c/a", it correctly uses the get /c/a route along with router middleware before it.
If I make a request to "/c/x", none of the routers middleware is used, only the application middleware is used.
If I make a request to "/e" which does not exist, none of the routers middleware is used, only the application middleware is used.

I would expect that "/c/x" would use the middleware for routerA and routerB which are before the "/c" nested router. I believe it should throw reach the final middleware in that route then be handled by the error handler on routerA.

I would expect that "/e" would use the middleware for routerA and routerB since it is used by the application without a path specified. That's what happens with nested routers like in the request to "/a", it has no matches in routerB but uses routerB middleware since use is called without a path before the route that was matched.

import { Application, Router } from "https://deno.land/x/oak@v10.0.0/mod.ts";

const routerB = new Router()
  .use(async (ctx, next) => {
    console.log("used routerB");
    await next();
  })
  .get("/b", (ctx) => {
    ctx.response.body = "used get /b";
  });

const routerC = new Router()
  .use(async (ctx, next) => {
    console.log("used routerB");
    await next();
  })
  .get("/", (ctx) => {
    ctx.response.body = "used get /c";
  })
  .use((ctx) => {
    ctx.throw(404);
  });

const routerA = new Router()
  .use(async (ctx, next) => {
    console.log("used routerA");
    await next();
  })
  .use(async (ctx, next) => {
    try {
      await next();
    } catch (error) {
      console.error(error);
      ctx.response.status = error.status;
      ctx.response.body = "used router errorHandler";
    }
  })
  .use(routerB.routes(), routerB.allowedMethods())
  .use("/c", routerC.routes(), routerC.allowedMethods())
  .get("/a", (ctx) => {
    ctx.response.body = "used get /a";
  })
  .get("/d", (ctx) => {
    ctx.throw(400);
  })
  .use((ctx) => {
    ctx.throw(404);
  });

const app = new Application();
app
  .use(async (ctx, next) => {
    console.log("used application");
    await next();
  })
  .use(async (ctx, next) => {
    try {
      await next();
    } catch (error) {
      console.error(error);
      ctx.response.status = error.status;
      ctx.response.body = "used application errorHandler";
    }
  })
  .use(routerA.routes(), routerA.allowedMethods())
  .use((ctx) => {
    ctx.throw(404);
  });

console.log("Listening on 8080");
await app.listen({ port: 8080 });

If I'm wrong on this, how do I get different error handling for different routes and ensure it is used when there is not a match? Is there a way to get the api's router middleware to be used even if there is not a match within it?

@KyleJune
Copy link
Author

I figured out a way to work around the above issue. I added an all handler for the path "/(.*)" as the last path for the router and have it throw a 404 error.

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

1 participant