Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grouped routing breaks RPC types #1512

Closed
sandervspl opened this issue Sep 27, 2023 · 8 comments
Closed

Grouped routing breaks RPC types #1512

sandervspl opened this issue Sep 27, 2023 · 8 comments
Labels

Comments

@sandervspl
Copy link

sandervspl commented Sep 27, 2023

What version of Hono are you using?

3.7.2

What runtime/platform is your app running on?

N/A

What steps can reproduce the bug?

Here is a reproduction. I have followed the RPC and grouped routing steps from the docs.

https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgCQgOwnAvnAZlCEOAIgAt0JiBuAKFElkTlIGNs8CiyKB6FgG2ABTNDGo0aLdAGd4AIwgQA1tLgBeOGiEB3FBQAUASlo0Fy6QDoA5kJj7iPYgBo4+lofUA+RDThwotgCuUGhwLBYAVtLoACr6CL5+cGYqAFxwMFCBQk6JWMY0+SZSaLJwAIZgYOqaOnoYRrQlZQSBMEKqGpVgFq3t9jwp0s7JiioFNDAAnmBCcACCVTEzcxrTsxC4-hBtHcUy8ALCojWsADyLYMuznvakMDBgqTw8-BAs5fzksqkAHADsAMcBSScBecAAegB+CTlaRTNBsXCBREwYDoOAgcrANBGHyg5rwALSSClVYVbTYw6CEQwCxDCwAEhsdhBSWaEH4Qgsbys+mJpOkQgKWAkWJxjRoQA

What is the expected behavior?

You should be able to write this without type errors. At least, there is nothing in the docs that says that this doesn't work.

client.books.$get()

What do you see instead?

You cannot write the above code without type errors

Additional information

No response

@sandervspl sandervspl added the bug label Sep 27, 2023
@NotoriousSledge
Copy link

Got this issue too when working with the Zod-to-openapi RPC-Client and using createRoute

@yusukebe
Copy link
Member

Hi @sandervspl , @exsjabe

This is not a bug, although it is hard to understand. You have to use the return value of books.get() like this.

const bookesRoutes = books.get("/", (c) => {
  return c.jsonT({
    books: true,
  });
});

The entire code is here.

@sandervspl
Copy link
Author

Right, that makes sense. I'd love to contribute to the docs but I'm not experienced enough yet to do so, but this would be really helpful to have in the docs!

@yusukebe
Copy link
Member

Okay!

I will close this issue and opened honojs/website#110. Thanks.

@MonsterDeveloper
Copy link
Contributor

MonsterDeveloper commented Oct 13, 2023

With this in mind, how should we structure big applications? All the routes in an endpoint should be defined in 1 constant for the type-safety to work.

import { Hono } from "hono";
import { hc } from "hono/client";

const app = new Hono();
const booksRouter = new Hono();
const storesRouter = new Hono();

// How to split this into multiple files?
const booksRoutes = booksRouter.get("/", c => c.jsonT({ books: "get" })).post(c => c.jsonT({ books: "post" }));

const storesRoutes = storesRouter.get("/", c => c.jsonT({ stores: "get" })).post(c => c.jsonT({ stores: "post" }));

const routes = app.route("/books", booksRoutes).route("/stores", storesRoutes);

type Routes = typeof routes;

const client = hc<Routes>("http://localhost:8787/");

@martinnormark
Copy link

This works for me.

index.ts file

import { serve } from '@hono/node-server';
import books from './books';
import stores from './stores';
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
import { swaggerUI } from '@hono/swagger-ui';

const app = new OpenAPIHono().basePath('/api/v1');
app.route('/books', books);
app.route('/stores', stores);

app.get(
	'/ui',
	swaggerUI({
		url: '/api/v1/doc',
	})
);

app.doc('/doc', {
	info: {
		title: 'Books API',
		version: 'v1',
	},
	openapi: '3.1.0',
	servers: [
		{
			url: '/api/v1',
		},
	],
});

serve(app);

books.ts file

import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';

const books = new OpenAPIHono().openapi(
	createRoute({
		method: 'get',
		path: '',
		responses: {
			200: {
				description: 'List of books',
				content: {
					'application/json': {
						schema: z.array(z.string()),
					},
				},
			},
		},
	}),
	(c) => {
		return c.json(["book 1", "book 2]);
	}
);

export default books;

stores.ts file

import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';

const stores = new OpenAPIHono().openapi(
	createRoute({
		method: 'get',
		path: '',
		responses: {
			200: {
				description: 'List of stores',
				content: {
					'application/json': {
						schema: z.array(z.string()),
					},
				},
			},
		},
	}),
	(c) => {
		return c.json(["store 1", "store 2]);
	}
);

export default stores;

@MonsterDeveloper
Copy link
Contributor

@martinnormark thanks! That's what I'm doing now as well. Yet the problem is that all the routes for an endpoint have to be defined in one variable for types to work properly.

@mhio
Copy link

mhio commented Nov 11, 2023

@MonsterDeveloper It's possible to export a union type that I believe emulates what hono builds for the single variable (at least I haven't run into any issues so far). I use this so I can define route associated items alongside the route functions, like schemas.

export const routes_rule = new Hono()

const schema_ruleRead = z.object({ id: z:string().length(32) })
const route_ruleRead = routes_rule.get(
  '/ruleRead/:id',
  zValidator('param', schema_ruleRead),
  async (c) => {
    const { id } = c.req.valid('param')
    const result = await readRule(id)
    return c.jsonT({ result })
  }
)

const schema_ruleUpdate = z.object({ rule: ZRule_Update })
const route_ruleUpdate = routes_rule.post(
  '/ruleUpdate',
  zValidator('json', schema_ruleUpdate),
  async (c) => {
    const { rule } = c.req.valid('json')
    const result = await processRuleUpdate(rule)
    return c.jsonT({ result })
  }
)

export type RoutesRule = 
  | typeof route_ruleRead
  | typeof route_ruleUpdate

The client can then be created with hc<RoutesRule> or the type is normally another union of all the exported route types. type RoutesApp = RoutesRule|RoutesY|Routes...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants