hono
hono copied to clipboard
[Feature] Override the serializer for json
What is the feature you are proposing?
It would be great to be able to easily override the serializer in req/res of c.json. I would like to use superjson to make date handling easier.
Hi @ShravanSunder
Honestly, I don't want to add more features to c.json()
, even though the changes might not be big.
Instead, you can use c.render()
and c.setRenderer()
:
https://hono.dev/api/context#render-setrenderer
@yusukebe Just so that i understand well, i would set my custom renderer with setRender and use that? I think that's a good fallback. Would this also work with hono stacks?
@ShravanSunder
Yes. You can write like the following though it will be a little bit verbose.
import { Hono } from 'hono'
const app = new Hono()
declare module 'hono' {
interface ContextRenderer {
(data: object): Response
}
}
app.get('/api/*', async (c, next) => {
c.setRenderer((data) => {
return c.body(JSON.stringify(data, null, 4))
})
await next()
})
app.get('/api/foo', (c) => {
return c.render({
foo: 'bar',
})
})
@yusukebe thanks!
One more question, is this method also possible to use with https://hono.dev/concepts/stacks
Ah, you want to use jsonT()
?
There might be someone using superjson
for RPC, but I can't recall it now. Hmm.
i think most specifically the handling of dates is the best thing out of superjson. Makes things uncomplicated
FWIW: I'm going to try the same (using setRenderer()
and render()
) to be able to "support" Infinity
and -Infinity
in JSON.
hmm i'm going to try this setrender pattern with msgpack
[update] worked perfectly, i'll test out the rpc stack in a bit
// @see https://github.com/honojs/hono/issues/1706
declare module "hono" {
interface CRParams {
data: Map<any, any>;
as?: string;
status: number;
}
interface ContextRenderer {
(opts: CRParams): Response;
}
}
players.get("*", async (c, next) => {
c.setRenderer(({ data, as = "msgpack", status }) => {
switch (as) {
// case "typed":
case "json":
return c.json(toJson(data), status);
case "string":
return c.text(toJsonStringified(data), status);
default:
return new Response(encoder.encode(data, { extensionCodec }), {
status,
headers: {
"Access-Control-Allow-Origin": "*",
...MSGPACK_HEADERS,
},
});
}
});
await next();
});
players.get("/", async (c) => {
// curl "localhost:3000/v1/players?as=json&pl=knoa&pl=nirvai"
// curl "localhost:3000/v1/players?as=string&pl=knoa&pl=nirvai"
// curl "localhost:3000/v1/players?pl=knoa&pl=nirvai"
const { as, pl } = c.req.queries();
return c.render({ as: as?.[0], data: await playersQuery.players(getBaseOpts({ names: pl })) });
});
I also hope to see this feature.
Although c.render can work well,
I believe using c.json
for handling JSON and c.render
for handling other more complex things would be more intuitive.
~~It would also prevent me from accidentally using the wrong method in different repository~~