I’m working on a Next.js application, and I have a method that calls an API from the server. This API sets a cookie, and I need to forward this cookie to the browser.
However, I’m facing a challenge:
- Server Actions: I can set cookies from server actions, but this requires triggering the method from the client side.
- Route Handlers: Alternatively, I can create a route handler, but this also needs to be called from the client side.
This approach doesn’t seem to leverage SSR effectively. Where is the SSR in this method? Is there a better way to achieve this in Next.js that fits within the SSR paradigm? Any guidance would be appreciated.
for example
export async function getData(): Promise<ServerState> {
const res = await fetch(`${getApiUrl()}/user`, {
method: 'GET',
headers: {
Cookie: cookies().toString(),
},
});
if (!res.ok) {
return {
status: ServerStateStatus.ERROR,
message: JSON.stringify(res),
};
}
// Revalidate user requests to pull in new payload
revalidateTag('user');
//here i am setting the response cookie so when i am doing this then i can't call it from server as in prod it throws error setting cookie is not allowed in server but when i am calling it from client it behaves like server action so works fine.
setServerCookies(response.headers.getSetCookie());
return {
status: ServerStateStatus.SUCCESS,
message: 'got the data',
};
}
//for ref
'use server';
import { ServerState, ServerStateStatus } from '@common-utils';
import { ResponseCookie } from 'next/dist/compiled/@edge-runtime/cookies';
import { cookies } from 'next/headers';
export interface Cookie {
name: string;
value: string;
[attr: string]: unknown;
}
export const setServerCookies = async (cookieArray: string[]) => {
cookieArray.forEach((cookieString) => {
const cookie: Cookie = { name: '', value: '' };
const parts = cookieString.split(';');
// Process the first part to extract name and value
const firstPart = parts.shift() || '';
const [name, value] = firstPart.trim().split('=');
cookie.name = name.trim();
cookie.value = value.trim();
parts.forEach((part) => {
const keyValue = part.trim().split('=');
// If there's no '=', it means it's a boolean attribute (e.g., httpOnly, secure)
if (keyValue.length === 1) {
const key = keyValue[0].trim();
cookie[key.charAt(0).toLowerCase() + key.slice(1)] = true;
} else {
const key = keyValue[0].trim();
const value = keyValue.slice(1).join('=').trim();
// Convert 'expires' field to Date if key is 'expires'
if (key === 'expires') {
cookie.expires = new Date(value);
} else {
cookie[key] = value;
}
}
});
// Set the cookie using Next.js cookies API
cookies().set(cookie as ResponseCookie);
});
};
I have done a bit of research on this found this discussion https://github.com/vercel/next.js/discussions/49843 but it didn’t gave me a way.