honojs / middleware

monorepo for Hono third-party middleware/helpers/wrappers
https://hono.dev
421 stars 145 forks source link

Skip content-type header check with zodValidator when targeting json? #594

Open zoubingwu opened 3 months ago

zoubingwu commented 3 months ago

I have an endpoint that can be requested with or without json body:

app.post("/endpoint", zValidator("json", zodRule), async (c) => {
    //...
})
### this should be ok
POST http://localhost:8787/endpoint

### this should also be ok
POST http://localhost:8787/endpoint
Content-Type: application/json

{"key": "value"}

but with zValidator targeting json, it will always check Content-Type header, see https://github.com/honojs/hono/blob/d21f8eb27aa43da9cd9d5b6f666692c4e92a0344/src/validator/validator.ts#L66-L73

any idea to optimize this behavior?

yusukebe commented 3 months ago

This is related to https://github.com/honojs/hono/issues/2651

zoubingwu commented 2 months ago

This is related to https://github.com/honojs/hono/issues/2651

@yusukebe i kinda feel like we are missing a way to pass a union-like validator so an api can accept multiple kinds of input, this is very useful for some api products.

for example:

zValidator(
  ['json', z.object()],
  ['form', z.object()],
  z.void(), 
)

this api can accept a json input or form input or void input

yusukebe commented 2 months ago

@zoubingwu

I'm not sure this will solve your problem, but we can write multiple validators like this:

const paramSchema = z.object({
  id: z.string()
})

const querySchema = z.object({
  q: z.string()
})

app.get('/foo/:id', zValidator('param', paramSchema), zValidator('query', querySchema), (c) => {
  // ...
})
zoubingwu commented 2 months ago

@yusukebe thanks, this is awesome, just learned something new! is there a way to make it to accept empty input too?

for example:

app.get('/foo/:id', zValidator('param', paramSchema), zValidator(z.void()), (c) => {
  // ...
})
yusukebe commented 2 months ago

Hi @zoubingwu

is there a way to make it to accept empty input too?

I can't understand it well. If you don't set validators for the body, such as json or form, it does not validate the body. Or should you limit the input to being empty?

zoubingwu commented 2 months ago

Yeah, my scenario is that an API can accept any empty input, as well as a JSON body as input.

like:

### this should be ok
POST http://localhost:8787/endpoint

### this should also be ok
POST http://localhost:8787/endpoint
Content-Type: application/json

{"key": "value"}

If I use zValidator, it won't work for both input (Error: Invalid HTTP header: Content-Type=undefined).

I can only instead perform the validation manually in the callback function.

zoubingwu commented 2 months ago
app.get('/foo/:id', zValidator('param', paramSchema), zValidator('query', querySchema), (c) => {
  // ...
})

I misunderstood a bit. Actually, in this way, each validator is in an "AND" relationship, this means that the input must satisfy each of the incoming validators.

But currently, there's a lack of an expression for an "OR" relationship, which means I can pass in multiple validators, but my API input only needs to satisfy one of them.