H
Hono4w ago
ricin

OpenAPI route with 204 + content: {} cause type error with c.body(null, 204)

This is probably a bug i tried many ways to solve it but i will either get a typecheck error on the handler or lose inference for that route altogether library versions:
@hono/zod-openapi 0.18.4 @hono/zod-validator 0.4.3 hono 4.8.5 minimal reproducible code:
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
content: {} // if i remove this line I lose type inference and handler won't typecheck anymore
},
},
});


const app = new OpenAPIHono().openapi(route, async (c) => {
return c.body(null, 204)
})
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
content: {} // if i remove this line I lose type inference and handler won't typecheck anymore
},
},
});


const app = new OpenAPIHono().openapi(route, async (c) => {
return c.body(null, 204)
})
Error diagnostics on .openapi():
Diagnostics:
1. Argument of type '(c: Context<Env, "/", {}>) => Promise<Response & TypedResponse<null, 204, "body">>' is not assignable to parameter of type 'Handler<Env, "/", {}, Promise<never>>'.
Type 'Promise<Response & TypedResponse<null, 204, "body">>' is not assignable to type 'Promise<never>'.
Type 'Response & TypedResponse<null, 204, "body">' is not assignable to type 'never'. [2345]
Diagnostics:
1. Argument of type '(c: Context<Env, "/", {}>) => Promise<Response & TypedResponse<null, 204, "body">>' is not assignable to parameter of type 'Handler<Env, "/", {}, Promise<never>>'.
Type 'Promise<Response & TypedResponse<null, 204, "body">>' is not assignable to type 'Promise<never>'.
Type 'Response & TypedResponse<null, 204, "body">' is not assignable to type 'never'. [2345]
So is there a way to have a no-content 204 response with openapi hono or is it not possible right now?
4 Replies
ambergristle
ambergristle4w ago
can you share a bit more about losing type inference when you remove the content parameter? that seems like the right way to document a 204: https://github.com/asteasolutions/zod-to-openapi?tab=readme-ov-file#registering-a-path-or-webhook
ricin
ricinOP4w ago
when removing content paramater hono wouldn't complain if you return wrong status code or body for example return c.body(null, 205) wouldn't cause typecheck error anymore. it also affects other independant status codes this will complain rightfully, number is not assignable to string in message property
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
content: {}
},
400: {
description: 'Bad request',
content: {
"application/json": {
schema: z.object({
message: z.string()
})
}
},
}
},
});

const app = new OpenAPIHono().openapi(route, async (c) => {
return c.json({ message: 123 }, 400)
})
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
content: {}
},
400: {
description: 'Bad request',
content: {
"application/json": {
schema: z.object({
message: z.string()
})
}
},
}
},
});

const app = new OpenAPIHono().openapi(route, async (c) => {
return c.json({ message: 123 }, 400)
})
this won't complain even though a 204 response is unrelated to 400
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
// content: {}
},
400: {
description: 'Bad request',
content: {
"application/json": {
schema: z.object({
message: z.string()
})
}
},
}
},
});

const app = new OpenAPIHono().openapi(route, async (c) => {
return c.json({ message: 123 }, 400)
})
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";

export const route = createRoute({
method: 'delete',
path: '/',
summary: 'Remove a resource',
request: {
},
responses: {
204: {
description: 'Holding removed successfully',
// content: {}
},
400: {
description: 'Bad request',
content: {
"application/json": {
schema: z.object({
message: z.string()
})
}
},
}
},
});

const app = new OpenAPIHono().openapi(route, async (c) => {
return c.json({ message: 123 }, 400)
})
ambergristle
ambergristle4w ago
ah, yeah. i see. that's unfortunate this seems related: https://github.com/honojs/middleware/issues/205 the fact that no-content responses break type-checking is sort of unexpected, though not entirely, as there are some limitations to how c.body works with Hono RPC as well
ricin
ricinOP4w ago
I will use 200 status code with simple json for DELETE responses even though 204 is more preferable for now as a work-around

Did you find this page helpful?