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

c.req.routePath returns a wrong value when used inside a custom middleware #3876

Closed
gormus opened this issue Jan 31, 2025 · 8 comments
Closed
Labels

Comments

@gormus
Copy link

gormus commented Jan 31, 2025

What version of Hono are you using?

4.6.16

What runtime/platform is your app running on? (with version if possible)

node

What steps can reproduce the bug?

When a custom middleware enabled for all routes matching a wildcard pattern, returns the same value for the c.req.routePath method used inside the middleware.

const app = new Hono()
  .use("/api/*", myMiddleware)
  .route("/api/users", user)
const app = new Hono()
  .put("/:id/anonymize", async (c) => {
    ...
    return c.json({ response }, 201)
  })
export const myMiddleware: MiddlewareHandler = async (c, next) => {
  const requestPath = c.req.routePath
  const requestMethod = c.req.method

  const route = allowedRoutes.find((r) => r.path === requestPath)

  // ... an access logic based on compared paths ...

  return c.json({ requestPath, requestMethod })
}

What is the expected behavior?

I expect the c.req.routePath method that run inside the custom middleware to return /api/users/:id/anonymize

What do you see instead?

... instead it returns the value defined in the use() method: /api/*

If no pattern is defined for the use(myMiddleware) method, it returns * for c.req.routePath method.

Additional information

Similar reports:

@gormus gormus added the triage label Jan 31, 2025
@yusukebe
Copy link
Member

yusukebe commented Feb 1, 2025

@gormus

This is not a bug. Expected behavior.

What you are seeing is the response from myMiddleware that returns a Response. Since myMiddleware is registered for /api/*, it is natural that /api/* is returned.

@yusukebe yusukebe added not bug and removed triage labels Feb 2, 2025
@gormus
Copy link
Author

gormus commented Feb 2, 2025

Thanks for your quick reply @yusukebe

Here's my confusion.

If I return the path details in put() method directly, I get this; and it is what I expect too:

  // Anonymize a user.
  .put("/:id/anonymize", async (c) => {
    return c.json({
      path: c.req.path,
      method: c.req.method,
      routePath: c.req.routePath,
      params: c.req.param(),
      url: c.req.url
    }, 200)
  })
{
  "path": "/api/users/52/anonymize",
  "method": "PUT",
  "routePath": "/api/users/:id/anonymize",
  "params": {
    "id": "52"
  },
  "url": "http://localhost:3000/api/users/52/anonymize"
}

But if I try to get the path details inside the middleware:

export const myMiddleware: MiddlewareHandler = async (c, next) => {
    return c.json({
      path: c.req.path,
      method: c.req.method,
      routePath: c.req.routePath,
      params: c.req.param(),
      url: c.req.url,
    }, 200)
}
{
  "path": "/api/users/52/anonymize",
  "method": "PUT",
  "routePath": "/api/*",
  "params": {},
  "url": "http://localhost:3000/api/users/52/anonymize"
}

I want to create a logic inside the middleware based on the routePath value, but actually for the routes passed through it.

I appreciate if you could point me to the right direction.

@EdamAme-x
Copy link
Contributor

@gormus
Copy link
Author

gormus commented Feb 2, 2025

Thanks @EdamAme-x, I thought about that too. but is this the best way?

    return c.json({
      path: c.req.path,
      method: c.req.method,
      routePath: c.req.routePath,
      params: c.req.param(),
      url: c.req.url,
      matchedRoutesFiltered: c.req.matchedRoutes.filter((r) => r.method === c.req.method),
      matchedRoutes: c.req.matchedRoutes,
    }, 200)

could return:

{
  "path": "/api/users/52/anonymize",
  "method": "PUT",
  "routePath": "/api/*",
  "params": {},
  "url": "http://localhost:3000/api/users/52/anonymize",
  "matchedRoutesFiltered": [
    {
      "path": "/api/users/:id/anonymize",      <-- The desired value
      "method": "PUT"                          <--   for matching method.
    }
  ],
  "matchedRoutes": [
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/*",
      "method": "ALL"
    },
    {
      "path": "/api/*",
      "method": "ALL"
    },
    {
      "path": "/api/users/:id/anonymize",
      "method": "PUT"
    }
  ]
}

@yusukebe
Copy link
Member

yusukebe commented Feb 2, 2025

@gormus

Do you need return c.json() in middleware? If return c.json() is unnecessary in middleware, you can get the expected values.

import { Hono } from 'hono'
import { createMiddleware } from 'hono/factory'

export const myMiddleware = createMiddleware(async (c, next) => {
  await next()
  const requestPath = c.req.routePath
  const requestMethod = c.req.method
  console.log(requestPath, requestMethod) // /api/users/:id/anonymize PUT
})

const user = new Hono().put('/:id/anonymize', async (c) => {
  return c.json({}, 201)
})

const app = new Hono().use('/api/*', myMiddleware).route('/api/users', user)

await app.request('/api/users/foo/anonymize', {
  method: 'PUT'
})

@gormus
Copy link
Author

gormus commented Feb 2, 2025

Thanks @yusukebe for the code example, and suggestions.

I had to do some more testing...

I realized calling await next() before const requestPath = c.req.routePath makes the real difference.

Calling await next() forces c.req.routePath to use the request detail that was passed through.

I was calling await next() as the last step in my complete middleware. I suppose that's why it wasn't getting the expected pattern.

@yusukebe
Copy link
Member

yusukebe commented Feb 3, 2025

@gormus Okay! Can you close this issue?

@gormus
Copy link
Author

gormus commented Feb 3, 2025

Not a bug indeed : ) Thanks for the support!

@gormus gormus closed this as completed Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants