connect-es icon indicating copy to clipboard operation
connect-es copied to clipboard

[connect-next] Example using new app routing

Open AshotN opened this issue 2 years ago • 8 comments
trafficstars

Is your feature request related to a problem? Please describe. I noticed there is a new package to work with NextJS but the example is based on Next 12.

Describe the solution you'd like I would appreciate some documentation on best practices when working with Next 13.

Describe alternatives you've considered Using the Next 12 pages style

AshotN avatar Mar 16 '23 17:03 AshotN

I tries to integrate Connect with Next via Middleware, there is an issue on Edge Runtime. It only supports subset of available Node.js APIs.

nicole0707 avatar Mar 17 '23 04:03 nicole0707

@AshotN, the new app directory in Next.js is still an experimental opt-in. We do not support it yet.

timostamm avatar Mar 17 '23 19:03 timostamm

Are there any plans for the near future?

AshotN avatar Mar 18 '23 09:03 AshotN

Hey @AshotN, yes we plan to support it. The first step was https://github.com/bufbuild/connect-es/pull/575 - it adds support for creating handlers using the fetch Request/Response types, which the new Route Handlers are using under the hood.

timostamm avatar Apr 11 '23 11:04 timostamm

Related discussion for support for edge runtimes: https://github.com/connectrpc/connect-es/discussions/829

timostamm avatar Sep 18 '23 14:09 timostamm

Any update on this?

samlee64 avatar May 17 '24 17:05 samlee64

I just set this up myself this weekend, it was pretty straightforward. I used the cloudflare workers example as reference. Here's the code others can use:

import {
  ConnectRouter,
  ConnectRouterOptions,
  createConnectRouter,
} from "@connectrpc/connect"
import {
  UniversalHandler,
  universalServerRequestFromFetch,
  universalServerResponseToFetch,
} from "@connectrpc/connect/protocol"

interface HandlerOptions extends ConnectRouterOptions {
  /**
   * Route definitions.
   */
  routes: (router: ConnectRouter) => void
  /**
   * The directory/prefix in which the Connect RPC server is mounted.
   */
  prefix: string
}

/**
 * Creates Next.js app route handlers for the given Connect service routes.
 */
export function nextAppRouter({ routes, prefix, ...options }: HandlerOptions) {
  const router = createConnectRouter(options)
  routes(router)
  const paths = new Map<string, UniversalHandler>()
  for (const handler of router.handlers) {
    paths.set(prefix + handler.requestPath, handler)
  }
  async function handler(req: Request) {
    const url = new URL(req.url)
    const handler = paths.get(url.pathname)
    if (handler === undefined) {
      return new Response(undefined, { status: 404 })
    }
    const uReq = universalServerRequestFromFetch(req, {})
    const uRes = await handler(uReq)
    return universalServerResponseToFetch(uRes)
  }
  return {
    POST: handler,
    GET: handler,
  }
}
// app/rpc/[[...connect]]/route.ts

export const { GET, POST } = nextAppRouter({
  prefix: "/rpc",
  routes(router) {
    // Register your service implementations here
    router.service(MyService, myServiceImpl)
  },
})

Mounting it at /rpc was of course an arbitrary choice, you could do /connect or wherever else, too. Your directory just needs to match your prefix parameter.

Are there other methods that need to be handled other than GET and POST? Maybe OPTIONS for people needing CORS? I didn't need that for my use case, and would be trivial enough to make your own OPTIONS handler function there to return the appropriate headers.

Hopefully this gets incorporated into a new plugin package or official example!

lourd avatar Jun 24 '24 04:06 lourd

Thanks @lourd !! that worked for me.

ivanvanderbyl avatar Aug 15 '24 03:08 ivanvanderbyl