Search code examples
next.jsurl-routing

NextJS case insensitive route for SSG pages


I am using NextJS to translate a CSV of data into static pages. Each page is pages/[slug].jsx. I'm calling toLowerCase() on the slug value inside [slug].jsx getStaticPaths() and getStaticProps() functions. The generated pages are lowercase. e.g. /ab101, /ab102, /cc500 all resolve to the pages/[slug].jsx page.

Unfortunately, people might hand type the url and may use caps or mixed case for the slug value, currently resulting in a 404.

QUESTION: How can I make routing case insensitive with respect to the slug value?

UPDATE

When I return fallback: true from getStaticPaths(), my [slug].jsx file is hit even when there is not an exact path match. I can then check isFallback as illustrated by Anish Antony below.

Additionally, the items param that is passed to my page will be undefined when the page wasn't found. The router's pathname value is "/[slug]" and not the value of "slug". However, there is an asPath value which contains useful data, e.g. /mixedCaseSlug?param=value&foo=bar.

When the page renders, I check if it's a fallback. If it is, show a LOADING... message. Next will display that and call getStaticProps() to generate the "missing" page. You'll then re-render with the page data. In the event that getStaticProps couldn't get page data, I push a path that will lead to the built-in 404 page.

export default function Page({ item }) {
  const { isFallback, push } = useRouter()
  const hasPageData = item && Object.keys(item).length > 0
  useEffect(() => {
    if (!isFallback && !hasPageData) {
      push('/page-not-found/error')
    }
  }, [isFallback, hasPageData])
  const loadingMsg = <div>Loading...</div>
  const notFoundMsg = <div>Page not found</div>
  return isFallback ? loadingMsg : hasPageData ? <Item item={item} /> : notFoundMsg
}

I needed to update getStaticProps() to lowercase the slug param, as it may now be mixed case, but we want to find our page data. And I needed to allow for the case when there really is no data for the slug.

export async function getStaticProps({ params }) {
  const { slug } = params
  const item = data.find(o => o.Practice_Code.trim().toLowerCase() === slug.toLowerCase())
  return {
    props: {
      item: item ? item : {}
    }
  }
}

This all seems very kludgy, so I'm still wondering if there is a better way.


Solution

  • NextJS routes are case sensitive.You can use fallback property in getStaticPaths to catch the routes which aren't in the same case as the one provided by default in getStaticPaths.

    Edit: I have updated the answer based on the discussion with Dave.

    We can give fallback:true or fallback:"blocking" , if we give fallback:true we we can show a custom component which will be displayed till the time page is loaded.For fallback:"blocking" new paths not returned by getStaticPaths will wait for the HTML to be generated,

    When we give fallback:true or "blocking" static page will be generated when the user first access the site and the generated page will be served for further visits.

    Sample code

    export async function getStaticPaths() {
      const idList = await fetchAllIds();
      const paths = [
      ];
      idList.forEach((id) => {paths.push(`/posts/${id}`)})
      return { paths, fallback: true };
    }
    

    What we have note is our code in getStaticProps should be case insensitive to get the data irrespective of the one provided in url.

    
    export async function getStaticProps({ params }) {
      const { slug } = params;
    
     try {
        /// This fetch api should be able to fetch the data irrespective of the case of the slug 
    or we should convert it to the required case before passing it as a parameter to API
        const data= await fetchSlugDetails(slug);
    //Same logic should be performed if you are getting data filtered based on slug from an existing array.
        return data? { props: { data} } : { notFound: true };
      } catch (error) {
        console.error(error);
        return { notFound: true };
      }
    
    }
    
    
    

    Note: You have to handle the notfound case and fallback case if you are using fallback:true. For fallback you can get the value isFallback from next/router while the page is being static generated