hono icon indicating copy to clipboard operation
hono copied to clipboard

[Feature] Override the serializer for json

Open ShravanSunder opened this issue 1 year ago • 10 comments

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.

ShravanSunder avatar Nov 16 '23 02:11 ShravanSunder

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 avatar Nov 16 '23 03:11 yusukebe

@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 avatar Nov 16 '23 20:11 ShravanSunder

@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 avatar Nov 16 '23 20:11 yusukebe

@yusukebe thanks!

One more question, is this method also possible to use with https://hono.dev/concepts/stacks

ShravanSunder avatar Nov 16 '23 23:11 ShravanSunder

Ah, you want to use jsonT()?

yusukebe avatar Nov 17 '23 10:11 yusukebe

There might be someone using superjson for RPC, but I can't recall it now. Hmm.

yusukebe avatar Nov 17 '23 10:11 yusukebe

i think most specifically the handling of dates is the best thing out of superjson. Makes things uncomplicated

ShravanSunder avatar Nov 17 '23 13:11 ShravanSunder

FWIW: I'm going to try the same (using setRenderer() and render()) to be able to "support" Infinity and -Infinity in JSON.

jvhellemond avatar Nov 17 '23 21:11 jvhellemond

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 })) });
});

noahehall avatar Nov 19 '23 14:11 noahehall

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~~

maou-shonen avatar Jun 18 '24 05:06 maou-shonen