honojs / hono

Web framework built on Web Standards
https://hono.dev
MIT License
20.19k stars 576 forks source link

endpoints returning raw values #2037

Closed mvolkmann closed 9 months ago

mvolkmann commented 9 months ago

What is the feature you are proposing?

Endpoint code could be simplified a bit if:

return someString; is equivalent to return c.text(someString); return someJSX; is equivalent to return c.html(someJSX); return someObject; is equivalent to return c.json(someObject);

EdamAme-x commented 9 months ago

like this?

    .get("/text", () => {
         const name = "hono";
         return `${name} is cool`;
    })
    .get("/jsx", () => {
        const name = "hono";
        return <html>
           {name} is cool
       </html>;
    })
    .get("/json" () => {
        const name  = "hono";
        return {
              [name]: "is cool"
        };
    });
yusukebe commented 9 months ago

As our primary principle, the handler must always return a Response object, so we do not implement it.

mvolkmann commented 9 months ago

I understand that a Response object must be returned, but couldn't Hono recognize when a Response object is not explicitly returned and automatically create the right kind of Response object based on the type of the value that is returned?

yusukebe commented 9 months ago

@moliveiraz

Yes, yes, we can do it. But we don't do it because it would increase the amount of code and we don't want users to rely on it because it can be done.

Also, this is my opinion, but I think that "always" returning a Response object is an easy API to understand.

mvolkmann commented 9 months ago

I thought perhaps I could implement my suggestion on my own. I can, but there are lots of battles with TypeScript types that I haven't figured out yet. But this does work:

import {enhance} from './honox.ts';

const app = new Hono();
enhance(app);

After doing this, I can write callbacks for app.get and the other endpoint methods that return a Response, a string, JSX, or an object. It correctly calls the write Context method to turn the result into a Response.

Here is honox.ts:

import {Context, Hono} from 'hono';

const methods = ['get', 'post', 'put', 'patch', 'delete'];

export function enhance(app: Hono) {
  for (const method of methods) {
    // @ts-ignore
    const original = app[T];

    // @ts-ignore
    app[T] = (...args: any[]) => {
      const lastIndex = args.length - 1;
      const callback = args[lastIndex];
      const enhancedCallback = async (c: Context): Promise<any> => {
        let result = callback(c);
        if (result instanceof Promise) result = await result;
        if (result instanceof Response) return result;
        if (typeof result === 'string') return c.text(result);
        if (result.constructor.name.startsWith('JSX')) return c.html(result);
        return c.json(result);
      };
      args[lastIndex] = enhancedCallback;
      original(...args);
    };
  }
}
yusukebe commented 9 months ago

You are right, you can do it yourself.

Also, v4 will implement similar features not in Hono core but in other places!