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

defaultHook not picked up in nested routes #2520

Open
marceloverdijk opened this issue Apr 17, 2024 · 2 comments
Open

defaultHook not picked up in nested routes #2520

marceloverdijk opened this issue Apr 17, 2024 · 2 comments
Labels

Comments

@marceloverdijk
Copy link

What version of Hono are you using?

4.2.4

What runtime/platform is your app running on?

Cloudflare Pages Functions

What steps can reproduce the bug?

Create a base app like below with a default hook handling validation errors:

export const createApp = () => {
  const app = new OpenAPIHono<Env>({
    defaultHook: (result, c) => {
      if (!result.success) {
        return c.json(
          {
            ok: false,
            errors: formatZodErrors(result),
            source: 'custom_error_handler',
          },
          422,
        );
      }
    },
  });
  app.use(logger());
  app.use(prettyJSON());
  app.use(async (c, next) => {
    const adapter = new PrismaD1(c.env.DB);
    const prisma = new PrismaClient({ adapter });
    c.set('prisma', prisma);
    await next();
  });
  return app;
}

Routes then directly connected to the app instance like will correctly use this defaultHook as expected, e.g.:

app.openapi(
  createRoute({
    method: 'get',
    path: '/api/pets/{id}',
    ..

but when nesting routes like:

app.route('/books', books);

the book routes will not use the defautHook as defined on the base app.

What is the expected behavior?

That the books routes will also use the defaultHook from the base app for handling validation errors.

What do you see instead?

No response

Additional information

No response

@marceloverdijk
Copy link
Author

See honojs/middleware#323

@marceloverdijk
Copy link
Author

marceloverdijk commented Apr 18, 2024

I'm reopening this issue becasue:

I have a create-app with:


export const createApp = () => {
  const app = new OpenAPIHono<Env>({
    defaultHook: (result, c) => {
      if (!result.success) {
        return c.json(
          {
            ok: false,
            errors: formatZodErrors(result),
            source: 'custom_error_handler',
          },
          422,
        );
      }
    },
  });
  app.use(logger());
  app.use(prettyJSON());
  app.use(async (c, next) => {
    console.log('setting prisma');
    const adapter = new PrismaD1(c.env.DB);
    const prisma = new PrismaClient({ adapter });
    c.set('prisma', prisma);
    await next();
  });
  return app;
};

it sets a defaultHook for handling validation errors but also applies logger, prettyJSON and a custom middleware that sets the Prisma client.

I created my root app like:

const app = createApp();

app.route('/api/pets', pets);
app.route('/api/events', events);
... more sub-routes

export const onRequest: PagesFunction<Env> = async (context) => {
  return app.fetch(context.request, context.env, context);
};

The sub-routes I was initially creating like:

const petsApp = new OpenAPIHono<Env>();

app.openapi(
  createRoute({
    method: 'get',
    path: '/',
    responses: {
      200: {
        description: 'OK',
        content: {
          'application/json': {
            schema: z.array(PetSchema),
          },
        },
      },
    },
  }),
  async (c) => {
    const pets = await c.var.prisma.pet.findMany({
      orderBy: { name: 'asc' },
    });
    const result: PetModel[] = petModelAssembler.toCollectionModel(pets);
    return c.json(result);
  },
);

export default petsApp;

Note that I'm using new OpenAPIHono<Env>() here, the createApp is only used for createing the root app and setting the defaults.

What this setup means for the pets sub-routes:

  • prisma var set
  • logger applied (as configured on the root app)
  • prettyJSON applied (as configured on the root ap)
  • defaultHook error handling not working

Now when using the createApp also to create the sub-routes app like const petsApp = createApp(); then:

  • prisma var set twice
  • logger applied twice
  • prettyJSONapplied
  • defaultHook applied

E.g. from logs for a single request:

<-- GET /api/pets/29
setting prisma
  <-- GET /api/pets/29
setting prisma
--> GET /api/pets/29 404 79ms
--> GET /api/pets/29 404 82ms

of course I could easily update my create-app.ts (which I did) to have createRootApp and createApp functions, but in general it feels inconsistent that middleware on the root app is propgated to child apps (using app.route(..)), but the defaultHook option is not.

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

1 participant