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

feat(events): bodyValidator and queryValidator event arguments #742

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

DallasHoff
Copy link

@DallasHoff DallasHoff commented Apr 30, 2024

πŸ”— Linked issue

unjs/nitro#2244

❓ Type of change

  • πŸ“– Documentation (updates to the documentation, readme, or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

These changes introduce bodyValidator and queryValidator options to defineEventHandler. These can be passed validation functions, such as a Zod schema's parse method, to validate request bodies and query parameters and type them in the handler.

export default defineEventHandler({
  bodyValidator: z.object({
    id: z.string()
  }).parse,
  handler: async (event) => {
    const { id } = await readBody(event);
    // id is inferred as a string now
  }
});

This will also allow Nitro to type the body and query options of $fetch since the required types of the body and query can now be inferred from the event handler, opening the door to...

await $fetch('/foo', {
  method: 'POST',
  body: {}, // <-- body inferred as { id: string } from the Zod Schema, so this is a TS error
});

See the associated pull request to Nitro: unjs/nitro#2405

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@pi0
Copy link
Member

pi0 commented May 1, 2024

Thanks for PR. Mind you we had been working on a more generic proposal validate key on eventhandler (#496). I'm more leaned towards supporting single validate rather than type specific separation (for body, query, params, etc)

@DallasHoff
Copy link
Author

DallasHoff commented May 3, 2024

I feel this solution is elegant for a few reasons:

  • No need for mutating the event or having type assertions anywhere (return event as EventWithValidatedBody)
  • Developers can easily type the body/query however they want whether its with a schema library or other function or if they have a type already defined somewhere else, they can just import it and pass it to defineEventHandler as a type argument.
type FooBody = {
  id: string;
}

export default defineEventHandler<FooBody>()
  • Defining the type in either of these ways automatically makes readBody and getQuery return the correct type.
  • On the reverse side, it's simple to infer the required body/query type from the handler if the developer needs to. h3 could also expose utility types to simplify it even further (e.g. HanderBody<T extends EventHandler>)
import fooHandler from 'api/foo';

type FooBody = typeof fooHandler extends EventHandler<EventHandlerRequest<infer Body>> ? Body : never;
  • No need to introduce a new function to h3
  • No real performance impact for projects that do not want to use this feature
  • In Nitro, it is now possible to make sure the route params, method, body, and query params in a fetch all match up. Entering one will narrow the others and give the corresponding auto-complete.
  • Keep in mind that most handlers will not have both a required body and query params, so having a generic validate function with extra steps to specify whether it validates the body or the query may not be as simple as having a dedicated option for each case.

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

Successfully merging this pull request may close these issues.

None yet

2 participants