Cannot modify cookies in a Server Action
Answered
YiÄŸithan posted this in #help-forum
Hello, I'm trying to delete cookies in a server action but I get this error:
(page.tsx)
(actions/get-projects.ts)
(api/client.ts)
Error: Cookies can only be modified in a Server Action or Route Handler.(page.tsx)
export default async function DashboardProjects({ searchParams }: DashboardProjectsProps) {
const { query } = searchParams;
const response = await getProjectsAction({ query });
return null;
}(actions/get-projects.ts)
'use server';
import { request } from '@/api/client';
import { GetProjectsParams, GetProjectsResponse } from '@/api/type';
export async function getProjectsAction({ query }: GetProjectsParams) {
const searchParams = new URLSearchParams();
searchParams.set('query', query);
const response = await request<GetProjectsResponse>('projects', searchParams);
return response;
}(api/client.ts)
import { cookies } from 'next/headers';
import { getServerSession } from '@/lib/auth';
export const request = async <T>(
path: string,
searchParams?: URLSearchParams,
requestOptions: RequestOptions = {
authCheck: true,
},
): Promise<RequestResponse<T>> => {
...
const response = await fetch(url, {
...requestOptions,
headers: {
'Content-Type': 'application/json',
...requestOptions?.headers,
},
cache: 'no-store',
});
let data: unknown = await response.json();
if (!response.ok) {
if (response.status === 401 && requestOptions.authCheck) {
console.log('clear server session');
cookies().delete('user'); // HERE IS THE PROBLEM
}
return {
status: 'error',
code: (data as ExternalErrorResponse).statusCode,
error: (data as ExternalErrorResponse).error,
message: await errorMessageParser((data as ExternalErrorResponse).message),
};
}
return {
status: 'success',
data: data as T,
};
};Answered by YiÄŸithan
I think I should get rid of external api as you suggested earlier
69 Replies
You are consuming your own API in the server which is meaning the server action req gets the cookie but not the client
You should run the contents/code of API directly instead
I need to use an external API, that's why I did it this way. Shouldn't I be able to manipulate cookies within the server action as I did above?
I want to manipulate the server-side cookie; I don't have any dealings with the client.
@YiÄŸithan I need to use an external API, that's why I did it this way. Shouldn't I be able to manipulate cookies within the server action as I did above?
you are effectively sending 2 requests
1. client to server action
2. server action to
this means that the client isn't involved with the second request, so you should either do the cookie directly, steal it from response headers and send or consume that api directly with client
1. client to server action
2. server action to
api/client.tsthis means that the client isn't involved with the second request, so you should either do the cookie directly, steal it from response headers and send or consume that api directly with client
If I consume the API on the client side, how will I do server-side rendering?
also i just realized, is your
api/client.ts in app dir or is it even nextjs?@YiÄŸithan If I consume the API on the client side, how will I do server-side rendering?
this is why you generally don't have it needed to do have your apis like this
@riský also i just realized, is your `api/client.ts` in app dir or is it even nextjs?
No, client.ts is not inside the app directory.
@riský this is why you generally don't have it needed to do have your apis like this
I need to use an external API because I can do some things on a remote server that I can't do on Next.js
sounds fair
ohh sorry i just realized that your api file wasn't what i thought it was (kinda messed up my recomendations)
Yes, I think you assumed it was inside the app directory.
nah i knew it wasn't
i just thought it was the api and not the wrapper
but now i am intrested to know why the cookies aren't working as you are using it in server context i thought
where is the error? build time or run time?
and can you try directly setting cookies in the root of action (as it should def know it is valid by there)
What do you mean by 'setting it directly'? 🤔
I tried, but even when I do it that way, I continue to get the same error.
Yes I am
well, that seems like a bug then 😓 , you should see if github issues has it, and if not try and make one (after a minimal example) - id test this myself but i don't really have time rn
When I write
'use server' at the top of the page.tsx file, I get the error "Error: A 'use server' file can only export async functions, found object." The issue may be related to this.that makes sense
you should never add that string unless you want it to be server action
and pages are usually not...
pages are server component by default
I should not get any error when I write
'use server' at the top of the page fileuse server doesn't actually mean that
it is for server actions
oh okay
i don't like the nameing tbh
many see 'use client' and want to do server version
yeah this is a way of using server actions
Then it shouldn't be used the way I'm using it. I guess it's not a bug.
@YiÄŸithan Then it shouldn't be used the way I'm using it. I guess it's not a bug.
oh yeah def, you should only use server actions on client
sorry that i kinda have only half looked at your code
@riský oh yeah def, you should only use server actions on client
like you showed or on form action
So I need to use route handlers
thank you for helping ðŸ™
you can just put the server action code inside the page
as it is done on server until a "use client" (but then SSRd, so kinda server too)
ah wait you are doing cookies
But I want to delete cookie
Yes 😄
yeah i forgot server components are readonly
you can use middleware or ig server actions called on client
I want to delete cookies If I get Unauthorized error from external api response.
cool cool
middleware should be able to work for you i believe
To use middleware for that purpose I need to send a request on middleware
middleware runs before your page is run
you can do redirections and things if you really want to do there too
yes that means I need to send auth control request on each navigation
well, you can set it to be only that page, so the same amount as currently
there are many pages need authentication
but if you use vercel you should know there are limits of like 1m per month i believe (opposed to normal "unlimited")
I think I should get rid of external api as you suggested earlier
Answer
yeah ,it seems like nextjs really isn't designed to not be full the backend