H
Hono3mo ago
Sun

Changing the response in the middleware breaks it

As seen on the #Extending the Context type , I'm trying to do an arriValidator now to create a new middleware for the @arrirpc/schema validator (like the zValidator, which should actually just be standard validator, but whatever) But, when I add the created arriValidator to the handler, the handler just doesn't return anything, even when the middleware clearly said for it to
export function arriValidator<T extends AObjectSchema>(schema: T): MiddlewareHandler {
const problemSchema = problemResponse(schema);

return async (c, next) => {
await next();

const responseData = await c.res.json();
return c.json({ message: "But why." });
// return respondWith(c, problemSchema, responseData);
};
}
export function arriValidator<T extends AObjectSchema>(schema: T): MiddlewareHandler {
const problemSchema = problemResponse(schema);

return async (c, next) => {
await next();

const responseData = await c.res.json();
return c.json({ message: "But why." });
// return respondWith(c, problemSchema, responseData);
};
}
export const routes = new Hono()
.get("/", arriValidator(HealthSchema), async (c) => {
return c.json({
message: "Health is OK!",
});
});
export const routes = new Hono()
.get("/", arriValidator(HealthSchema), async (c) => {
return c.json({
message: "Health is OK!",
});
});
See response information on image
No description
26 Replies
Sun
SunOP3mo ago
Without the middleware:
export const routes = new Hono()
.get("/", async (c) => {
return c.json({
message: "Health is OK!",
});
});
export const routes = new Hono()
.get("/", async (c) => {
return c.json({
message: "Health is OK!",
});
});
No description
ambergristle
ambergristle3mo ago
reading the response like that (in the middleware) and returning a new response is definitely not how you want to be going about it ig the source code does allow for a response to be overwritten. im not sure why the data doesn't get passed through a naive read is that the content-length header is getting overwritten here: https://github.com/honojs/hono/blob/c18c2b2e0992d15e530a69c7db6b9ccbd6f06e61/src/context.ts#L685 and that may be messing with the response
Sun
SunOP3mo ago
that's private? also doesn't json return a response? same as the middleware so shouldn't it just like, use the middleware response instead?
ambergristle
ambergristle3mo ago
private?
Sun
SunOP3mo ago
this.#headers # = private
ambergristle
ambergristle3mo ago
yeah, but it's used in response construction and it's not as simple as "just use the middleware response" because as soon as you read the response in the middleware, you flip a (private) boolean flag that bypasses default response construction and goes into some more complicated logic that seems like it's merging responses
Sun
SunOP3mo ago
I mean, Context#json/1 returns a response.... also I'm like, super lost on what you mean there
ambergristle
ambergristle3mo ago
mean where?
Sun
SunOP3mo ago
everything :d like, why can't I just use c.json's return value, why can't I just mutate the response directly, stuff that should be simple not being as simple
ambergristle
ambergristle3mo ago
this is the first time i've taken a close look at how hono constructs responses, so i'm still trying to figure out how everything works whether it should be simple or not, i can't say. but calling c.json multiple times in the course of a request doesn't just cleanly override the response and calling c.res.json before calling c.json for a second time definitely changes the way that hono processes the response
Sun
SunOP3mo ago
not documented side effects alert
ambergristle
ambergristle3mo ago
there are many places the docs could be clearer, but tbf i don't think that the way you're trying to manipulate the response is common or "expected" behavior you could try taking a look at the trpc-server middleware, but i expect there's an easier solution
Sun
SunOP3mo ago
I mean, how else would I return a invalid response if not by mutating it
ambergristle
ambergristle3mo ago
well, the only thing that could be invalid is the actual data which you could validate before returning a response at all e.g.,
// ...
const { body, status } = constructResponse(data, Schema)
return c.json(body, status)
// ...
const { body, status } = constructResponse(data, Schema)
return c.json(body, status)
Sun
SunOP3mo ago
this on the middleware? I'm lost here again
ambergristle
ambergristle3mo ago
no, just in the handler
Sun
SunOP3mo ago
that's what I have though, I want something like zValidator instead, showing the validator errors
ambergristle
ambergristle3mo ago
well, zValidator is for request data, not response data, which is an important difference hono-openapi has (experimental) response validation, so you could take a look at how they do that
Sun
SunOP3mo ago
I plan on doing for both, so that's just a first step
ambergristle
ambergristle3mo ago
looks like it clones the response, checks the cloned response data, and throws an error if the data is bad: https://github.com/rhinobase/hono-openapi/blob/c166811df2c1b34f821575e38046ce61c175f88b/packages/core/src/route.ts#L37 but modifying hono's behavior to that extent requires a strong command of typescript, and a pretty deep understanding of how hono works so i'd recommend spending some time understanding the hono source code
Sun
SunOP3mo ago
welp, I don't really have time for that for just returning simple validators responses so I'll just copy zvalidator and not do stuff
ambergristle
ambergristle3mo ago
why don't you just use the hono RPC client then?
Sun
SunOP3mo ago
wdym? sry for being late here ah, that's the one that uses zValidator, I don't like zod wait, can I just trick hono into using Context#render/1 for a json renderer instead? wait, it changes nothing
ambergristle
ambergristle3mo ago
No. Hono has an RPC client that’s validation-agnostic It’s part of the core library and entirely type-based
Sun
SunOP3mo ago
I mean, the example just uses zvalidator instead of whatever hono has
ambergristle
ambergristle3mo ago
zValidator is just a thin layer over hono/validator, like most (if not all) of the third-party validation middleware regardless, that only affects the request data typing, if you choose to use it it has nothing to do with the response typing at all

Did you find this page helpful?