1

What happened here is I want to use Next.js's SSG using getStaticPaths combined with getStaticProps. Everything was working fine in dev. But when I run the build command, it throws an error like this:

A required parameter (id) was not provided as a string in getStaticPaths for /mentor/[id]

My folder structure look like this:

|- pages
   |- api
      |- mentors
         |- [id].ts
         |- index.ts
   |- mentor
      |- [id].tsx
   |- _app.tsx
   |- _document.tsx
   |- index.tsx

My mentors API look like this:

pages/api/mentors/index.ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export default (req: NextApiRequest, res: NextApiResponse) => {
  res.status(200).json(mentors);
};

My mentors/:id API look like this:

pages/api/mentors/[id].ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export default (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query;
  const selectedMentor = mentors.find((mentor) => mentor.id.toString() === id);
  res.status(200).json(selectedMentor);
};

The dummyDatas look like this:

utils/dummyDatas.ts

export const mentors: MentorType[] = [
  {
    id: 1,
    name: "John Doe",
    description:
      "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Rerum quidem earum perferendis, facilis quos vero, nobis maxime explicabo quo adipisci modi a ducimus? Dicta labore delectus consequatur sint, nisi temporibus.",
    image:
      "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80",
  },
  ...
]

Now with all that resources, I want to try SSG and here's my code implementing the SSG.

pages/mentor/[id].tsx

import axios from "axios";
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next";

// Components
import { MentorDetail } from "containers";
import { MentorType } from "utils/types";
import { Header } from "molecules";

interface IProps {
  mentor: MentorType;
}

function Detail({ mentor }: IProps) {
  return (
    <>
      <Header loggedIn={false} />
      <MentorDetail mentor={mentor} />
    </>
  );
}

export const getStaticPaths: GetStaticPaths = async () => {
  try {
    const { data } = await axios.get("http://localhost:3000/api/mentors");
    const paths = data.map((mentor: MentorType) => {
      return {
        params: { id: mentor.id.toString() },
      };
    });
    return {
      paths,
      fallback: false,
    };
  } catch {
    return { paths: [{}], fallback: false };
  }
};

export const getStaticProps: GetStaticProps = async (
  context: GetStaticPropsContext
) => {
  try {
    const { data } = await axios.get(
      `http://localhost:3000/api/mentors/${context.params.id}`
    );
    return {
      props: {
        mentor: data,
      },
    };
  } catch {
    return {
      props: {},
    };
  }
};

export default Detail;
juliomalves
  • 42,130
  • 20
  • 150
  • 146
Mikeul
  • 51
  • 1
  • 7

1 Answers1

1

The issue most likely happens because during build-time your request is failing, and as such the catch block is returning an empty paths array.

You should not call an internal API route from getStaticProps/getStaticPaths. See this related answer for details: Fetch error when building Next.js static website in production.


You'll need to slightly refactor your API routes code to export its logic.

// pages/api/mentors/[id].ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export const getMentorById = (id: string) => mentors.find((mentor) => mentor.id.toString() === id);

export default (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query;
  const selectedMentor = getMentorById(id);
  res.status(200).json(selectedMentor);
};

Then in your getStaticPaths you'll want to directly import the mentors data.

// pages/mentor/[id].tsx

import { mentors } from "<path-to>/utils/dummyDatas"; // Replace with your actual path to the file

export const getStaticPaths: GetStaticPaths = async () => {
    const paths = mentors.map((mentor: MentorType) => {
        return {
            params: { id: mentor.id.toString() }
        };
    };

    return {
        paths,
        fallback: false
    };
};

And in your getStaticProps you'll want to reuse the getMentorById function defined in your API route, rather than making a request.

// pages/mentor/[id].tsx

import { getMentorById } from "<path-to>/api/mentors/[id]" // Replace with your actual path to the file

export const getStaticProps: GetStaticProps = async (context: GetStaticPropsContext) => {
    const data = getMentorById(context.params.id);

    return {
        props: {
            mentor: data
        }
    };
};
juliomalves
  • 42,130
  • 20
  • 150
  • 146