0

I have set up a NEXTJS app that is under a subdomain and basically the structure is the following:

/Pages->

--/Sites

--/api

--/home

--/subdomain_logic

--_app.tsx

...config files...

As of this moment, if you go to domain.com you will be landing into another app that I developed so there is nothing configured outside of subdomain logic. If you go to subdomain.domain.com then you get all the logic ocurring into subdomain_logic. I want to set api routes but nextjs doesn't allow to set them outside of your api folder and if I leave them there those routes actually belong the domain.com app that I have in isolation. How would you create api routes on my situation?

Here is my middleware.ts file:

import { NextRequest, NextResponse } from "next/server";

export const config = {
  matcher: [
    "/",
    "/([^/.]*)", // exclude `/public` files by matching all paths except for paths containing `.` (e.g. /logo.png)
    "/site/:path*",
    "/post/:path*",
    "/_sites/:path*"
  ]
};

export default function middleware(req: NextRequest) {

  const url = req.nextUrl;

  const pathname = req.nextUrl.pathname.toString();

  const hostname = req.headers.get("host");

  if (!hostname)
    return new Response(null, {
      status: 400,
      statusText: "No hostname found in request headers"
    });

  const currentHost =
    process.env.VERCEL_ENV === `production` ||
    process.env.VERCEL_ENV === `preview`
      ? 
        hostname
          .replace(`.domain.com`, "")
          .replace(`${process.env.VERCEL_URL}`, "")
          .replace(`${process.env.NEXT_PUBLIC_VERCEL_URL}`, "")
      : hostname.replace(`.localhost:3000`, "");

  if (pathname.startsWith(`/_sites`))
    return new Response(null, {
      status: 404
    });

  if (
    !pathname.includes(".")
  ) {
    if (currentHost === "subdomain") {
      if (
        pathname === "/login" &&
        (req.cookies["next-auth.session-token"] ||
          req.cookies["__Secure-next-auth.session-token"])
      ) {
        url.pathname = "/";
        return NextResponse.redirect(url);
      }

      url.pathname = `/subdomain${url.pathname}`;
      console.log(url);
      return NextResponse.rewrite(url);
    }
    url.pathname = `${pathname}`;
    return NextResponse.rewrite(url);
  }
}

I would like to set up properly NextAuth if that give more clues into what could be the solution for my problem. Thanks for the help!

  • Can you please share your `_middleware` file or explain how you have setup your subdomain redirect. – Devon Ray Jul 08 '22 at 10:23
  • I see NEXTJS has basePath but that seems to be more for specific linking within the app instead of actual routing. Do you think there is something on my middleware file I can do regarding API routes? – Nicolás Guasca Santamaría Jul 08 '22 at 11:59
  • 1
    I'm not sure I fully understand the issue. Assuming your Next.js app runs under your subdomain (`subdomain.domain.com`), then the API routes you setup will be available under `subdomain.domain.com/api/example-endpoint`. Is that an issue? – juliomalves Jul 10 '22 at 17:01

1 Answers1

0

So where you are doing your redirect you basically want to do a check if its the api directory and not run those rewrites. Not sure what some of your code is doing but here is something that i am doing in a project with a similar setup.

If you reference your api endpoints via either the main or the subdomain it should still route correctly.

I am a bit confused by your question and how you are looking to integrate next auth, feel free to drop a comment if i've misunderstood anything.



 import { NextRequest, NextResponse } from "next/server";

export default function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl;

  const url = req.nextUrl.clone();

  let hostname = req.headers.get("host");
  hostname = hostname?.split(":")[0] ?? null;

  const rootUrls = `${process.env.ROOT_URLS}`.split(",");

  // only continue if its not a custom domain happening.
  if (!rootUrls?.includes(hostname!)) {
    // get the current subdomain or custom domain
    const currentHost = hostname!.replace(`.${process.env.ROOT_URL}`, "");

    if (pathname.endsWith("sitemap.xml")) {
      url.pathname = `/_sites/${currentHost}/sitemap`;
      return NextResponse.rewrite(url);
    }

    if (pathname.endsWith("robots.txt")) {
      url.pathname = `/_sites/${currentHost}/robots`;
      return NextResponse.rewrite(url);
    }

    // fail if trying to access the site directory
    if (pathname.startsWith(`/_sites`)) {
      return new Response(null, { status: 404 });
    }
    if (pathname.startsWith(`/_sites_previews`)) {
      return new Response(null, { status: 404 });
    }

    if (
      !pathname.includes(".") && // exclude all files in the public folder
      !pathname.startsWith("/api") // exclude all API routes
    ) {
      if (req.nextUrl.searchParams.get("preview")) {
        url.pathname = `/_sites_previews/${currentHost}${pathname}`;
      } else {
        url.pathname = `/_sites/${currentHost}${pathname}`;
      }
      // rewrite to the current hostname under the pages/sites folder
      // the main logic component will happen in pages/sites/[site]/index.tsx
      return NextResponse.rewrite(url);
    }
  }
}


Devon Ray
  • 401
  • 4
  • 12
  • Thank you for your reply Devon! The thing I need to deal with is the api routes that belong to the App that is hosted by subdomain.domain.com because if I leave them in the folders they are, they will actually be calling the routes I have on other app that is hosted under domain.com. I decided to move my subdomain logic outside of its folder and taking it to pages (taking Julio's suggestion) and now its working well! – Nicolás Guasca Santamaría Jul 13 '22 at 10:47