question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

hi again 😃

so in exploring trpc, they have some adapters, I took a stab at modifying their fetch adapter to work with hono, but I’d love some feedback on if this looks okay:

import { AnyRouter, inferRouterContext, resolveHTTPResponse } from '@trpc/server';
import { HTTPBaseHandlerOptions, HTTPRequest } from '@trpc/server/dist/http/internals/types';
import type { Context,  } from 'hono';
import { StatusCode } from 'hono/utils/http-status';

export type HonoCreateContextFn<TRouter extends AnyRouter> = (opts: {
  ctx: Context;
}) => inferRouterContext<TRouter> | Promise<inferRouterContext<TRouter>>;

export type HonoCreateContextOption<TRouter extends AnyRouter> =
  unknown extends inferRouterContext<TRouter>
    ? {
        /**
         * @link https://trpc.io/docs/context
         **/
        createContext?: HonoCreateContextFn<TRouter>;
      }
    : {
        /**
         * @link https://trpc.io/docs/context
         **/
        createContext: HonoCreateContextFn<TRouter>;
      };

export type HonoHandlerOptions<TRouter extends AnyRouter> = HTTPBaseHandlerOptions<
  TRouter,
  Request
> &
  HonoCreateContextOption<TRouter>;
export type HonoHandlerRequestOptions<TRouter extends AnyRouter> = {
  ctx: Context;
  endpoint: string;
} & HonoHandlerOptions<TRouter>;

export async function honoRequestHandler<TRouter extends AnyRouter>(
  opts: HonoHandlerRequestOptions<TRouter>
): Promise<Response> {
  const createContext = async () => {
    return opts.createContext?.({ ctx: opts.ctx });
  };

  const url = new URL(opts.ctx.req.url);
  const path = url.pathname.slice(opts.endpoint.length + 1);
  const req: HTTPRequest = {
    query: url.searchParams,
    method: opts.ctx.req.method,
    headers: Object.fromEntries(opts.ctx.req.headers),
    body: await opts.ctx.req.text(),
  };

  const result = await resolveHTTPResponse({
    req,
    createContext,
    path,
    router: opts.router,
    batching: opts.batching,
    responseMeta: opts.responseMeta,
    onError(o) {
      opts?.onError?.({ ...o, req: opts.ctx.req });
    },
  });

  for (const [key, value] of Object.entries(result.headers ?? {})) {
    if (typeof value === 'undefined') {
      continue;
    }

    if (typeof value === 'string') {
      opts.ctx.header(key, value);
      continue;
    }

    for (const v of value) {
      opts.ctx.header(key, v);
    }
  }
  return opts.ctx.body(result.body, result.status as StatusCode);
}

Usage:

import { serve } from '@honojs/node-server';
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { initTRPC } from '@trpc/server';
import { honoRequestHandler } from './common/trpc';

const t = initTRPC.create();

const appRouter = t.router({
  userById: t.procedure
    .input((val: unknown) => {
      if (typeof val === 'string') return val;
      throw new Error(`Invalid input: ${typeof val}`);
    })
    .query(req => {
      const { input } = req;

      return { hello: 'world' };
    }),
});

const app = new Hono();

app.use('*', logger());

app.get('/', c => c.text('working :~)'));

app.use('/trpc/*', c => {
  return honoRequestHandler({
    router: appRouter,
    ctx: c,
    endpoint: 'trpc/',
  });
});

serve(app);

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:24 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
yusukebecommented, Oct 5, 2022

I wonder if it could also live in the hono repo/org? @honojs/trpc-adapter?

Ah, yes. It is also good to make it @honojs/trpc-adapter. Both are good.

Since tRPC is so popular, I think it would be better to have it placed in that tRPC repository because it would be used by more people 😃

For example, we could create @honojs/trpc-adapter and put examples of Hono in tRPC examples.

By the way, this is a different issue, but I am thinking of changing the way to manage Third-party Middleware. Specifically, I’m thinking of making it monorepo. In that case, it may take some time to create @honojs/trpc-adapter.

3reactions
aulneaucommented, Oct 15, 2022

I think this approach is great too, but I think trpc should also be supported, as they have a large ecosystem of tooling. For folks who aren’t using trpc already, this approach could get them very close to a similar experience.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Usage with Express - tRPC
tRPC includes an adapter for Express out of the box. This adapter lets you convert your tRPC router into an Express middleware. server.ts....
Read more >
Official tRPC adapters
tRPC includes an adapter for the native Fetch API out of the box. This adapter lets you convert your tRPC router into a...
Read more >
Usage with the Fetch API - tRPC
This adapter lets you convert your tRPC router into a Request handler that returns Response objects. Example apps​. Description, Links. Cloudflare Workers ...
Read more >
Usage with AWS Lambda through the API Gateway - tRPC
tRPC includes an adapter for API Gateway out of the box. This adapter lets you run your routes through the API Gateway handler....
Read more >
Awesome tRPC Collection
Description, Link. tRPC-SvelteKit - SvelteKit tRPC extension, https://github.com/icflorescu/trpc-sveltekit. tRPC-Remix - Adapter for Remix ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found