1

I am going through the Next.js official documentation. I am using the App router. On the data fetching patterns page, it's mentioned:

Whenever possible, we recommend fetching data on the server

So, I wrote this simple function:

import 'server-only'

export async function getData() {
    const res = await fetch('http://localhost:3333/<endpoint>');
   
    if (!res.ok) {
      // This will activate the closest `error.js` Error Boundary
      throw new Error('Failed to fetch data')
    }

    return await res.json();
}

But the api I need to call, require the jwt token in the authorisation header, and I can't access localStorage on server-side.

So, the next thing I did is, I made my function take the token as an input parameter:

import 'server-only'

export async function getData(token) {
    const res = await fetch('http://localhost:3333/<endpoint>', {
      headers: {
        Authorization: `Bearer ${token}`
      }
    });
   
    if (!res.ok) {
      // This will activate the closest `error.js` Error Boundary
      throw new Error('Failed to fetch data')
    }

    return await res.json();
}

But the problem here is, in order to use this function, I need to import this in my client component, which is an unsupported pattern. (I tried this, and I am getting the relevant error.)

If I need to import this function, I will have to eventually make the data-fetching code run on client environment only, which is against the first recommendation (whenever possible, fetch data on server).

My question here is:

  1. Is it possible to somehow pass the current request context(including http headers), to the function that needs to run on server, so that I can extract the token out on the server?
  2. Or, am I just trying to break the pattern here? Is it more like, for protected data, I should not fetch it on server side, but on the client side?

I am considerably new to Next.js or frontend dev in general. I am trying to get around this since yesterday, and am finally looking for help.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Vikas Prasad
  • 3,163
  • 5
  • 28
  • 39

1 Answers1

2

You can't access the localStorage API from the server-side. It is recommended to use the server-side for data fetching.

So you can store your JWT token in cookies instead of localStorage. Because you can access the cookies in any server-side component, you will be able to send that in your request headers.

You can write/read the cookies like this in the Next.js 13 app directory.

Write:

'use server'
 
import { cookies } from 'next/headers'
 
async function create(data) {
  cookies().set('name', 'lee')
  // or
  cookies().set('name', 'lee', { secure: true })
  // or
  cookies().set({
    name: 'name',
    value: 'lee',
    httpOnly: true,
    path: '/',
  })
}

Good to know: .set() is only available in a Server Action or Route Handler.

Read:

import { cookies } from 'next/headers'
 
export default function Page() {
  const cookieStore = cookies()
  const theme = cookieStore.get('theme')
  return '...'
}

Read this guide for more information: https://nextjs.org/docs/app/api-reference/functions/cookies

Musab
  • 149
  • 1
  • 8
  • I can start using cookies instead of localStorage, but the problem is I cannot import the server only function inside my client component even then. Then, how do I access the server-fetched data on my client side? – Vikas Prasad Aug 30 '23 at 05:51
  • okay, I solved it. I was doing a basic mistake. Instead of trying to call the server-only function inside my client component where I needed the server fetched data, the right way to do it was, call the function to fetch the data in a parent server component, then use your client component and pass the fetched data as a prop to it. This way you will have access to the server fetched data inside your client component. Doing above^, and then on server side reading the token from cookies instead of `localStorage` as suggested by you, I was able to solve this. Thanks for the guidance. – Vikas Prasad Aug 30 '23 at 07:46