Skip to content
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

Nextjs routes #227

Open
majeed4u opened this issue Jun 12, 2023 · 2 comments
Open

Nextjs routes #227

majeed4u opened this issue Jun 12, 2023 · 2 comments

Comments

@majeed4u
Copy link

not working with nextjs 13 app directory api

i have trieded many times

@Chinmay0905
Copy link

What problems are you facing?

@stephyswe
Copy link

stephyswe commented Jul 1, 2023

So... Next-connect, The example provided looks like it is used in "one file"
I will refer as nextjs pages as "pages", and nextjs-13 as "app".

Example with nextjs-13: https://github.com/hoangvvo/next-connect/blob/main/examples/nextjs-13/src/app/api/users/route.ts

But the beauty of next-connect seems to be it can be defined as a "centralized hub" for api routes.

In "Pages" app shown here you can create a wrapper with next-connect

/api/shows/index.ts

const handler = createHandler();
handler.get(async (req: NextApiRequest, res: NextApiResponse) => {
  let shows = await getShows();

  // generate shows if there aren't any
  if (shows.length === 0) {
    await generateData();
    shows = await getShows();
  }

  return res.status(200).json({ shows });
});

createHandler is stored in a api/handler file.

import type { NextApiRequest, NextApiResponse } from "next";
import nextConnect from "next-connect";

import { validateToken } from "@/lib/auth/utils";

import { processApiError } from "./utils";

// base handler for centralized error and method handling
export const createHandler = ({
  authRequired,
}: { authRequired?: boolean } = {}) => {
  const handler = nextConnect({
    onError(error, req: NextApiRequest, res: NextApiResponse) {
      const { status, message } = processApiError(error);
      res.status(status).json({ message });
    },
    onNoMatch(req: NextApiRequest, res: NextApiResponse) {
      res.status(405).end(`Method ${req.method} Not Allowed`);
    },
  });
  if (authRequired) {
    handler.use(async (req, res, next) => {
      const tokenIsValid = await validateToken(req);
      if (!tokenIsValid) return res.status(401).end();
      return next();
    });
  }
  return handler;
};

With this setup. We don't need to add useSession in every page.tsx file. It can be handled during api call as well.

// As example an reservation page - requires authenticated calls
const handler = createHandler({ authRequired: true });
handler.post(async (req: NextApiRequest, res: NextApiResponse) => {

My own attempt of doing in "app":

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
import { createEdgeRouter } from "next-connect";

import { validateToken } from "@/lib/auth/utils";

import { processApiError } from "./utils";

// base handler for centralized error and method handling
export const createHandler = ({
  authRequired,
}: { authRequired?: boolean } = {}) => {
  const handler = createEdgeRouter<NextRequest, NextFetchEvent>();
  handler.handler({
    onError(error, req, res) {
      const { status, message } = processApiError(error);
      NextResponse.json( { message },{ status });
    },
    onNoMatch(req, res) {
      NextResponse.json(`Method ${req.method} Not Allowed`);
    },
  });
  if (authRequired) {
    handler.use(async (req, res, next) => {
      const tokenIsValid = await validateToken(req, req.nextUrl.searchParams.get("userId"));
      if (!tokenIsValid) return NextResponse.json({status: 401});
      return next();
    });
  }
  return handler;
};

Used in route.ts /api/shows/ as:

export async function GET(req: Request) {
  return handler.get(async (req: Request) => {
    let shows = await getShows();

    // generate shows if there aren't any
    if (shows.length === 0) {
      await generateData();
      shows = await getShows();
    }

    return NextResponse.json({ shows });
  });
}

But I don't get it working yet because I think nextConnect wrapper is used in handler.ts

EDIT:
Continuing on this. Looking at the types for "Old" nextConnect is

export default function <Req = IncomingMessage, Res = ServerResponse>(
    options?: Options<Req, Res>
  ): NextConnect<Req, Res>;

In new one it alittle different.

export { createEdgeRouter } from "./edge.js";
export { expressWrapper } from "./express.js";
export { createRouter } from "./node.js";
export type { HandlerOptions, NextHandler } from "./types.js";

One thing that gets me , most of times, is people built perfect libraries but then when it refactored many use-cases in the old ones are lost for "faster" way of writing. Having a page with "old code" - for this scenario. Here's the exact same scenario but with using new version.
This is such a bummer for developers who are really used using older libraries and to their capabilities only to be thrown down into the bottom, to re-learn everything yet again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants