-
-
Notifications
You must be signed in to change notification settings - Fork 655
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
Pure RPC client types #2489
Comments
How a found a little way to make this work: Below is a pure type that does not care about the contents of route implementation. For now I am just going to create a separate library with such types for each router... export type AppType = Hono<
Env,
ToSchema<
'get',
'/hello',
{
query: {
test: string;
};
},
Promise<
TypedResponse<{
hello: string;
}>
>
>,
'/'
>;
const client = hc<AppType>('localhost');
client.hello.$get({ query: { test: 'hello' } }); |
I tried the same thing but with const route = createRoute({
method: 'get',
path: '/hello',
request: {
params: z.object({ test: z.string() }),
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({ hello: z.literal('world') }),
},
},
description: 'Get hello!',
},
},
});
const api = new OpenAPIHono();
const APP = api.openapi(route, function () {} as any);
const client = hc<typeof APP>('localhost');
const req = await client.hello.$get({ param: { test: '123123' } });
const res = await req.json();
// === "world"
console.log(res.hello) This gave me full control over the types I have in my client, so I managed to create a whole client without any actual code. This same |
Hi @askorupskyy Is the matter resolved? If not, please provide a minimal project to reproduce it. I'll investigate. |
I'll make a project and tag you in a couple hrs. I found a hack around original Hono type behavior but this would be nice to have as a part of the framework. This little hack that I put above worked for me and actually reduced the amount of |
https://github.com/askorupskyy/hono-rpc-types I created a simple project that explains the issue. Follow the README and the code |
Thanks! |
I read through some more issues and I think using my proposal would also fix #1921. Seems like one of the cases I covered in the README to my repo |
Hmm. I'm trying it, but I'm not so familiar with Nx, and I can't understand what causes the issue. I think it's fine to simply make it emit |
@yusukebe Nx in my case is just used to demonstate some of the bugs the current type system might cause. The main problem is Hono client needs to infer all the types from routes directly, which causes all of the code inside At my company we've been using tRPC which had a similar issue. It was building too many types and causing our builds to fail due to lack of RAM. We later switched to ts-rest, which creates the types in advance, similar to what #1921 is proposing,
Essentially what I did in this repo is a created the It would be nice to declare your route types in Hono the same way as in ts-rest. |
This syntax would work better: // declare a router
const createUserRouter = createRouter({
method: 'POST',
input: // either a TS type or a zod object
output: // just a TS type
}) // implement a router
// use generics to make sure what you are implementing matches the type of the declaration
const router = new Hono().post<typeof createUserRouter>('/user', (c) => c.json(new User())) // create a client
const client = hc<typeof createUserRouter>(); This way the client only depends on the type of the declaration, not the entire business logic of the app. |
@askorupskyy Thanks for explanation. In the future, we may add a Validator that validates Response (#2439), so if we can infer the type from that Validator, we will not need to generate the type from the entire Hono application. |
Either way, this is not a problem that can be solved right away. I'd like to take some time to think about it. |
Plus. As you @askorupskyy mentioned above, the one way to solve this issue is using Zod OpenAPI. Because it is designed to declare endpoint types explicitly. So, we may not have to make Hono core's type inferences more complicated to support this matter. Just use Zod OpenAPI. |
@yusukebe thank you so much! i did not initially realize zod-openapi resolves this matter completely |
@yusukebe, I believe this change may have broken ZodOpenAPI type inferrence: |
@yusukebe I spoke with a few more people encountering the same issue as I did (not only with Hono, but tRPC, Elysia and etc), so I wrote a little library that solves this matter for me & my team. It's built on top of The code for this thing looks something like this: ![]() Router implementation on the right, definition on the left. Both are in separate buildable npm libs for faster build times and reusability. The main difference is now I only need to build the code on the left in order to have an API client, which was not possible before. This resulted about 1/3 speedup in build time for our project and not exposed any backend code/types to the web client except for the actual route definition. I do not think it's that much of a breaking change to Hono, but it definitely solves a good chunk of problems for its community. I will post this library on my account whenever it's polished enough to be used. Let me know if you have any questions. |
Hi @askorupskyy Does it generate a |
@askorupskyy have you seen https://github.com/msutkowski/ts-rest-hono ? |
Sorry for disappearing guys, a lot of stuff happened. Either way, I found a way to make everything work, and after quite a long pause I am able to continue working on this little library.
Yeah, it does exactly what I am talking about. I just don't like how it's not maintained anymore. Also middleware is not really supported well either.
No, everything is done through type inference. I essentially just made a bunch of wrappers for I was able to save a bunch of time on builds, as well as keep the global types different on backend and frontend. ![]() |
I come with "dumb newbie" solution instead rewrite all into zod-openapi Just create define the type api
and consume the type Api by create wrapper helper function
And we can consume like this
Hope this help |
Hey all. Try to this way: https://hono.dev/docs/guides/rpc#compile-your-code-before-using-it-recommended |
@askorupskyy Are you interested in publishing or sharing the implementation of I'm also coming from ts-rest land and have my code set up in that convention, but I'm struggling with my IDE build times and wondering if the approach you're describing to type inference will resolve that |
What is the feature you are proposing?
The problem
I was using Hono for one of my monorepo projects and one of the problems I have is that it fails to compile whenever the process environments are different.
Some to code to better explain:
API environment
This below contains all sorts of stuff the API might need, like DB connection strings, payment credentials...
Nextjs web client environment
Compile issues:
How since the Hono RPC client is just the representation of the API, it should not care for missing environment type definitions on the backend.
However, when compiled, (I use
Nx
withesbuild
), the frontend application complains about missing backend environment types, even though this stuff should be abstracted.I should not need the
REDIS_URL
to be inprocess.env
within my Nextjs app, however, Hono makes me do this...Possible fix:
Now I've done some digging and it does not make sense to build ALL of the routes, including their actual implementations in order to have a client type.
It would make much more sense to have a
route type
, aka input->output definition, from which the client would be constructed. The actual routers would then import this type and have the actual logic.This, in pair with
zod-openapi
package would make Hono a killer RPC platform.How do Hono's competitors achieve this?
I've also been using https://ts-rest.com/, which follows pretty much the same pattern I'm proposing here. The only difference is ts-rest follows full OpenAPI specs for their API definitions.
For example,
This code below describes the type of the router (the client inherits directly from here...)
The text was updated successfully, but these errors were encountered: