Directly import next.js API endpoint in getServerSideProps()

Viewed 2577

When fetching data using getServerSideProps() in Next.js, they recommend directly importing the API endpoint instead of using fetch() and running another HTTP request. This makes sense, and I was able to get it working until implemented middleware for my API (note, I'm using the API feature built into Next.js). Now with middleware implemented, I can't export functions that use the middleware, I have to export the handler. See below:

const handler = nextConnect();
handler.use(middleware);

handler.get(async (req, res) => {
    const post = await req.db.collection("posts").findOne();
    res.send({
        post: post,
    });
});

export default handler;

What would be the recommend way to import my API endpoint into getServerSideProps? I would like to do something as follows, but the getPost() function no longer has access to the database middleware:

export const getPost = async () => {
    const post = await req.db.collection("posts").findOne();
    return post;
}

handler.get(async (req, res) => {
    res.send({
        post: getPost(),
    });
});

and then in my next.js page:

import { getPost } from './api/post';
...
export async function getServerSideProps(context) {
    return {
        props: {
            post: getPost(),
        }
    }
}
1 Answers

In any case, you'll have to pass the req and res objects to the function. But if you do the following, the post prop should be populated with a NextApiResponse instance, which at it's base is a stream.Writable object, which is probably not what you want...

import { getPost } from './api/post';
...
export async function getServerSideProps({req, res}) {
  return {
    props: {
      post: await getPost(req, res),
    }
  }
}

You could try to read the stream, but that seems like more trouble than refactoring your code, but if you call getPost(req, res).end(), I think you should get the streamed data, but I'm not sure how it will be formatted. You'd have to check.

You could split your functions up a little more..

// In your api endpoint:
const handler = nextConnect();
handler.use(middleware);

export async function getPostMethod(db) {
  return await db.collection("posts").findOne();
}

handler.get(async (req, res) => {
  res.send({
    post: await getPostMethod(req, res, req.db)
  })
});

export default handler;

// In your page component:

export async function getServerSideProps({req, res}) {
  // Do what ever you have to do here to get your database connection
  const db = await whereIsMyDb()
  return {
    props: {
      post: await getPostMethod(db),
    }
  }
}
Related