Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internal API fetch with getServerSideProps? (Next.js)

I'm new to Next.js and I'm trying to understand the suggested structure and dealing with data between pages or components.

For instance, inside my page home.js, I fetch an internal API called /api/user.js which returns some user data from MongoDB. I am doing this by using fetch() to call the API route from within getServerSideProps(), which passes various props to the page after some calculations.

From my understanding, this is good for SEO, since props get fetched/modified server-side and the page gets them ready to render. But then I read in the Next.js documentation that you should not use fetch() to all an API route in getServerSideProps(). So what am I suppose to do to comply to good practice and good SEO?

The reason I'm not doing the required calculations for home.js in the API route itself is that I need more generic data from this API route, as I will use it in other pages as well.

I also have to consider caching, which client-side is very straightforward using SWR to fetch an internal API, but server-side I'm not yet sure how to achieve it.

home.js:

export default function Page({ prop1, prop2, prop3 }) {
        // render etc.
}

export async function getServerSideProps(context) {
  const session = await getSession(context)
  let data = null
  var aArray = [], bArray = [], cArray = []
  const { db } = await connectToDatabase()

  function shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex;
    while (0 !== currentIndex) {
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }
    return array;
  }

  if (session) {
    const hostname = process.env.NEXT_PUBLIC_SITE_URL
    const options = { headers: { cookie: context.req.headers.cookie } }
    const res = await fetch(`${hostname}/api/user`, options)
    const json = await res.json()
    if (json.data) { data = json.data }

    // do some math with data ...
    // connect to MongoDB and do some comparisons, etc.
like image 359
m4tt Avatar asked Jan 16 '21 18:01

m4tt


People also ask

Can I use fetch in Nextjs?

Data fetching in Next. js allows you to render your content in different ways, depending on your application's use case. These include pre-rendering with Server-side Rendering or Static Generation, and updating or creating content at runtime with Incremental Static Regeneration.

What is getServerSideProps in Nextjs?

getServerSideProps or API Routes An API route is used to fetch some data from a CMS. That API route is then called directly from getServerSideProps . This produces an additional call, reducing performance. Instead, directly import the logic used inside your API Route into getServerSideProps .

Where can I use getServerSideProps?

If you want to render a page at the time of the request, you can use getServerSideProps to render a page on the server before responding to a request. getServerSideProps will mark the page to be rendered on each request.

What is difference between getStaticProps and getServerSideProps?

getStaticProps(): A method that tells the Next component to populate props and render into a static HTML page at build time. getServerSideProps(): A method that tells the Next component to populate the props and render into a static HTML page at run time.


1 Answers

But then I read in the Next.js documentation that you should not use fetch() to all an API route in getServerSideProps().

You want to use the logic that's in your API route directly in getServerSideProps, rather than calling your internal API. That's because getServerSideProps runs on the server just like the API routes (making a request from the server to the server itself would be pointless). You can read from the filesystem or access a database directly from getServerSideProps.

From Next.js getServerSideProps documentation:

It can be tempting to reach for an API Route when you want to fetch data from the server, then call that API route from getServerSideProps. This is an unnecessary and inefficient approach, as it will cause an extra request to be made due to both getServerSideProps and API Routes running on the server.

(...) Instead, directly import the logic used inside your API Route into getServerSideProps. This could mean calling a CMS, database, or other API directly from inside getServerSideProps.

(Note that the same applies when using getStaticProps/getStaticPaths methods)


Here's a small refactor example that allows you to have logic from an API route reused in getServerSideProps.

Let's assume you have this simple API route.

// pages/api/user
export default async function handler(req, res) {
    // Using a fetch here but could be any async operation to an external source
    const response = await fetch(/* external API endpoint */)
    const jsonData = await response.json()
    res.status(200).json(jsonData)
}

You can extract the fetching logic to a separate function (can still keep it in api/user if you want), which is still usable in the API route.

// pages/api/user
export async function getData() {
    const response = await fetch(/* external API endpoint */)
    const jsonData = await response.json()
    return jsonData
}

export default async function handler(req, res) {
    const jsonData = await getData()
    res.status(200).json(jsonData)
}

But also allows you to re-use the getData function in getServerSideProps.

// pages/home
import { getData } from './api/user'

//...

export async function getServerSideProps(context) {
    const jsonData = await getData()
    //...
}
like image 150
juliomalves Avatar answered Sep 23 '22 06:09

juliomalves