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

Are there plans to support the new Route Handlers API?

Open jmikrut opened this issue 1 year ago • 13 comments

Hey there - just found this package and it looks amazing.

Question - are there any plans to support the new route handlers API? Reviewing the documentation, it seems like there will be some incompatibilities as of now. But maybe they could be solved.

Thanks in advance!

jmikrut avatar Mar 16 '23 00:03 jmikrut

up

volnei avatar Mar 28 '23 20:03 volnei

Please, any news?

Nicolab avatar Apr 24 '23 10:04 Nicolab

The new route handler can almost replace this lib. However, it should still work if you use this if you want to take advantage of this lib's middleware setup.

const router = createEdgeRouter<NextRequest, NextFetchEvent>();
router.use(this);
router.use(that);
router.get(something);
router.post(something);

export async function GET(...params) {
  return router.run(...params);
}

export async function POST(...params) {
  return router.run(...params);
}

hoangvvo avatar Apr 24 '23 18:04 hoangvvo

Just curious, why the new route handler replaces this lib? How can I get the advantage of intercepting handlers?

volnei avatar Apr 24 '23 18:04 volnei

Thank you for your reply @hoangvvo

In fact it is to use passport.js which integrates as Express.js middleware. I haven't found a way to make it work directly in Next 13 (app folder). I'm hopeful it will work with next-connect.

By the way, good question from @volnei

Nicolab avatar Apr 24 '23 18:04 Nicolab

Thank you for your reply @hoangvvo

In fact it is to use passport.js which integrates as Express.js middleware. I haven't found a way to make it work directly in Next 13 (app folder). I'm hopeful it will work with next-connect.

By the way, good question from @volnei

I am also using passport/magic link and the bedrock framework which uses next-connect. @hoangvvo can you provide more details on how it can be 'almost' replaced? What part can't?

cordial avatar Apr 24 '23 18:04 cordial

@Nicolab,

Currently I'm using a proprietary solution to intercepting routes by creating an wrapper that do everything I need.

I just supose that it can help you with passport also.

Something like:

export function intercept(init: InteceptInit): (request: NextRequest, { params }?: any) => Promise<NextResponse> {
    return async function (request: NextRequest, { params }: any): Promise<NextResponse> {
        try {
            // resolve authentication (proprietary) from request.
            let auth = await resolve(request)
            if (init.secure && auth instanceof Anonymous) throw new AuthError(401, 'Not authenticated')

            // parse request input using Zod
            let body = await request.json().catch((e) => {})
            let parsed
            if (init.schema) {
                parsed = await init.schema.parseAsync({
                    params,
                    search: Object.fromEntries(new URL(request.url).searchParams.entries()),
                    body,
                })
            }
            // get a DB connections
            let db = await connect()
            return await init.handler({ request, parsed, auth, db })
        } catch (error) {
            if (error instanceof ZodError) return new ZodErrorHandler().handle(error)
            if (error instanceof AuthError) return new AuthErrorHandler().handle(error)
            return new InternalServerErrorHandler().handle(error as Error)
        }
    }
}

and

export const GET = intercept({
      handler: async () => {
          // api handler
      },
      schema: z.object({}) // my Zod schema,
      secure: true | false // if it required authentication or not
})

volnei avatar Apr 24 '23 18:04 volnei

For me, the biggest inconsistency / expected trouble using this package in the app folder comes from the fact that the NextRequest / NextResponse are now quite a bit different from the typical Express-like req / res.

For example, headers are no longer able to be set via res.setHeader. Lots of existing Express middlewares are written expecting Express-like req / res and are broken no matter what I tried to do on my own in the app folder.

I will attempt to follow the instructions @hoangvvo has mentioned. We are interested in using this package to deploy Payload within a Next app seamlessly.

We are using Passport and many other Express middlewares, and so I don't think the app folder on its own can replace this package for us.

jmikrut avatar Apr 24 '23 18:04 jmikrut

For me, the biggest inconsistency / expected trouble using this package in the app folder comes from the fact that the NextRequest / NextResponse are now quite a bit different from the typical Express-like req / res.

For example, headers are no longer able to be set via res.setHeader. Lots of existing Express middlewares are written expecting Express-like req / res and are broken no matter what I tried to do on my own in the app folder.

I will attempt to follow the instructions @hoangvvo has mentioned. We are interested in using this package to deploy Payload within a Next app seamlessly.

We are using Passport and many other Express middlewares, and so I don't think the app folder on its own can replace this package for us.

I see. I think a shim package to make express middleware compatible with the new NextRequest instance would be interesting. I will look into it.

hoangvvo avatar Apr 25 '23 11:04 hoangvvo

@hoangvvo you are a boss. If you are interested in this work, Payload will happily sponsor you!

jmikrut avatar Apr 28 '23 18:04 jmikrut

I've recently been working on something very much in the direction of @volnee's implementation. A high-level overview is that we'd implement a similar function pattern as above with a range of config options like Zod (probably other validation libraries over time) validation schemas, auth callback's for protected routes, middleware and other nice to haves like onErrorHandlers etc.

So far I've been able to successfully pass the types from the Zod Schemas into a context object that the router handler itself receives as a parameter. Hoping the below snippet of the function being utilised provides a little more context.

import { UserClass } from "lib";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";

import { withRequestContext } from "../../factories/api";

const postQueryVal = z.object({
  lang: z.enum(["en", "es", "fr"]).default("en"),
});

type PostQueryVal = z.infer<typeof postQueryVal>;

export const POST = withRequestContext(
  {
    validation: {
      query: postQueryVal,
    },
  },
  async (request, ctx) => {
    // Will be handled by the provided validation object and be defaulted / processed as defined in the schema
    console.log(ctx.query.lang);
    // Body validation not provided, so type of body is assumed to be never
    console.log(ctx.body.foo);
    return NextResponse.json({ hello: "world" });
  }
);

export type { PostQueryVal };

I'm thinking I'll push the code to a repo once I've added in the relevant logic to receive callbacks for validating auth on protected routes as well as middleware functions. Would anyone be interested in collaborating on something like that?

slongdotexe avatar Apr 29 '23 07:04 slongdotexe

Would anyone like to try handleNextRequest from https://github.com/hoangvvo/next-connect/pull/232 ? (just copy the app-route.ts file to your project and run it like this:

// src/app/[[...rest]]/route.ts

import express from 'express'
import payload from 'payload'
import { AppRouteRequestHandler, handleNextRequest } from './app-route'

const app = express()
app.get(...)

export const GET: AppRouteRequestHandler = (req) => handleNextRequest(req, app)

thgh avatar Jul 11 '23 23:07 thgh