h3
h3 copied to clipboard
support additional generic for typing incoming body & query
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 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
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
Will be glad to help you guys on this stuff 🚀
Feel free to initiate h3-typebox @kevinmarrec ❤️ You can use unjs/template for starter.
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)
})
I just forgot this issue. @kevinmarrec Do you mind to open a PR to add your nice package to the readme?
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 ❤️
@pi0 I opened the PR :)
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.
But how do you plan to type
useBody
call withindefineEventHandler
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.
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 🙏🏻
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.