h3 icon indicating copy to clipboard operation
h3 copied to clipboard

support additional generic for typing incoming body & query

Open danielroe opened this issue 2 years ago • 10 comments

would support something like this:

export default defineEventHandler<{ result: string }, { foo: string }>(async event => {
  const { foo } = await useBody(event)
  return {
    result: foo
  }
})

const result = await $fetch('/api/test', {
  body: {
    // auto-completing body, requiring 
  }
})

Follow-up tasks

  • [ ] add support for typing query/body in Nitro generated types & ohmyfetch (via options)

possibly could also consider params?

danielroe avatar Jun 04 '22 08:06 danielroe

@danielroe Does useQuery & useBody already provides generic type ?

I also had schema validation Idea that could be implemented within the composables, like useBody handling bad requests using JSON schema type builder like https://github.com/sinclairzx81/typebox . useBody could then infer type from schema

kevinmarrec avatar Jun 04 '22 09:06 kevinmarrec

Love the ideas!

useBody accepts type generic (useParams doesn't. PR welcome to add!)

We can introduce request validation with an external package like h3-typebox exposing useValidatedBody(event) with type inference and wrapping useBody. Later we might introduce a built-in util based on ajv/untyped or more h3 tailored DX.

I guess would be safer if we namespace second genetic for extensibility like { body: {}, query: {} }. But how do you plan to type useBody call within defineEventHandler without explicitly giving generic to it @danielroe

pi0 avatar Jun 04 '22 13:06 pi0

Will be glad to help you guys on this stuff 🚀

kevinmarrec avatar Jun 04 '22 13:06 kevinmarrec

Feel free to initiate h3-typebox @kevinmarrec ❤️ You can use unjs/template for starter.

pi0 avatar Jun 04 '22 13:06 pi0

Now, this is awesome! With express and zod for example, you can type the body like this:

import { Request, RequestHandler, Response } from 'express';

export const validateRequestBody: <TBody>(
  zodSchema: ZodSchema<TBody>,
) => RequestHandler<ParamsDictionary, any, TBody, any> = (schema) => (req, res, next) => {
  const parsed = schema.safeParse(req.body);
  if (parsed.success) {
    return next();
  } else {
    return res.status(400).send(parsed.error)
  }
};
import { validateRequestBody } from './validation'
import { z } from 'zod';

app.get("/", validateRequestBody(
    z.object({
      name: z.string(),
      age: z.number(),
    })
  ), (req, res) => {
    // req.body is now strictly-typed and confirms to the zod schema above.
    // req.body: { name: string, age: number };
  }
);

I think we should accept any TypeScript schema validator (zod,typebox,yup). I'm thinking something like:

import { z } from 'zod'
import { someResolverFn } from 'your-library'

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

useValidatedBody(event, {
  resolver: someResolverFn(schema)
})
import { object, string, number } from 'yup'
import { someResolverFn } from 'your-library'

const schema = object({
  name: string().required(),
  age: number().required().positive().integer()
})

useValidatedBody(event, {
  resolver: someResolverFn(schema)
})

wobsoriano avatar Jun 09 '22 17:06 wobsoriano

I just released h3-typebox (source) 🚀

Feedbacks are welcome !

kevinmarrec avatar Jun 12 '22 12:06 kevinmarrec

I just forgot this issue. @kevinmarrec Do you mind to open a PR to add your nice package to the readme?

pi0 avatar Aug 03 '22 18:08 pi0

I would personnaly rename it to h3-validator (but fine with h3-typebox if listed in Readme as validator options) and support the new event object @kevinmarrec 😊

Awesome work so far ❤️

Atinux avatar Aug 04 '22 09:08 Atinux

@pi0 I opened the PR :)

kevinmarrec avatar Aug 04 '22 09:08 kevinmarrec

I would personnaly rename it to h3-validator (but fine with h3-typebox if listed in Readme as validator options) and support the new event object @kevinmarrec 😊

This issue is still open for a built-in validation. Conventionally, by using the integration name in h3-[integration] we can support other possible validators from community.

pi0 avatar Aug 04 '22 09:08 pi0

But how do you plan to type useBody call within defineEventHandler without explicitly giving generic to it @danielroe

It might be possible by passing down the annotations to the event parameter which could then allow readBody to infer it from there.

septatrix avatar Mar 05 '23 21:03 septatrix

Hi,

I see this issue as close but the $fetch typed part was not working (in nuxt) and i can't find any issue in the nuxt repository about this.

In the h3 repo it's ok, we have the generic and readBody was working.

What's the actual state for this ?

Thank's for all your hard work 🙏🏻

aspitrine avatar Sep 04 '23 20:09 aspitrine

In the PR closing this it is explicitly stated that using this for $fetch within nuxt is something which still has to be done. It is likely best if you create a new issue in the nuxt repository for tracking that.

septatrix avatar Sep 04 '23 20:09 septatrix