hoangvvo / next-connect

The TypeScript-ready, minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2

Home Page:https://www.npmjs.com/package/next-connect

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Are there plans to support the new Route Handlers API?

jmikrut opened this issue · 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!

Please, any news?

commented

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);
}

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

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

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?

@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
})

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.

commented

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 you are a boss. If you are interested in this work, Payload will happily sponsor you!

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?

Would anyone like to try handleNextRequest from #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)