Next.js Discord

Discord Forum

Is it bad practices to mix return values and redirects in server actions?

Answered
Brown bear posted this in #help-forum
Open in Discord
Brown bearOP
Hi, I have some server actions to submit data, I am checking there if there is no auth state I redirect to login, if the action is successful it will redirect to another page but if it has error it then returns the error which I plan to show in the frontend, is this bad practice mixing redirects and returns in a server action?
Answered by LuisLl
Sounds good to me. That’s completely valid. As long as you're using Server Actions to mutate data (submit, or modify or delete, any of this kind) and read the result from the operation. Do not use them exclusively to fetch data because that approach has footguns you will want to avoid.

I assume you’re gonna use useActionState to read the return values of the Server Action, if not that's still ok, they're just async functions that become POST endpoints under the hood.
View full answer

77 Replies

Sounds good to me. That’s completely valid. As long as you're using Server Actions to mutate data (submit, or modify or delete, any of this kind) and read the result from the operation. Do not use them exclusively to fetch data because that approach has footguns you will want to avoid.

I assume you’re gonna use useActionState to read the return values of the Server Action, if not that's still ok, they're just async functions that become POST endpoints under the hood.
Answer
@LuisLl Well not a bad practice really. That’s also valid.👍
Brown bearOP
alright thnx
@Brown bear alright thnx
Of course, I updated my reply to provide more useful info.
@LuisLl Of course, I updated my reply to provide more useful info.
Brown bearOP
hey man do you have any idea, why a server action when being called directly inside a promise callback in client side gives this error
failed to forward action response TypeError: fetch failed
Can you show the code of the server action? And the place in your code where you're calling it.
Brown bearOP
yes
This is my action
export const submitCheckoutStepAccount = async (): Promise<{ success: boolean; error: unknown } | undefined> => {
    const locale = await getLocaleFromHeadersOrDefault();

    const token = getAuthTokenFromCookies();

    if (!token) {
        redirect(`/${locale}/register?redirectUrl=/${locale}/checkout`, RedirectType.push);
    }

    let isSuccess = false;
    let error = null;

    try {
        const headers = getHeaders();
        headers.Authorization = `Bearer ${token}`;
        const user = decodeJwt(token);
        const data = await httpClient
            .url("/api/checkout/account/default")
            .headers(headers)
            .post({ customerId: user.username })
            .json<TCheckoutStepAccountResponse>();
        if (data && data.sessionId) {
            setCheckoutSessionId(data.sessionId);
            isSuccess = true;
        }
    } catch (err) {
        isSuccess = false;
        error = err;
    }

    if (isSuccess) {
        redirect(`/${locale}/checkout`, RedirectType.push);
    }

    return {
        success: isSuccess,
        error: error,
    };
};
Does this happen on dev mode only? Or production? Or both?
Brown bearOP
I have not deployed in production
in dev is happening
also I forgot to mention
this action I am calling in 2 places
I am calling in another page /cart
and it works fine because if it doesn't have a token it is redirecting to login properly
but then from login is no longer working
I logged in middleware the pathname for some reason it is showing the /cart when the action is called in the login page
Server Actions come with a lot of hidden issues, I've noticed they usually run into race conditions, maybe this is happening
Server Actions run in serial, not parallel, which means one call needs to be completed before the other executes. Are you for some reason triggering both calls secuentially?
Brown bearOP
no
ahhh
but the login action
it sets the cookie
I have await login()
and after that I am calling that other action
Mmmh could be that, because both are called from the same endpoint, somehwat. Under the hood server actions become POST requests fired from the current url you're on.
Brown bearOP
before i had login as a route handle
I had same issue
then I tried to move both as server actions
maybe now I should try both as route handlers
Ugh I wish I could be more useful on this one but I've never faced that issue
Brown bearOP
no problem just was wondering if you had this issue before, or if I am breaking some rules
because its my first time using server actions
WAIT
and if you await the call? await handlePostLogin();
You are firing it but maybe you run into race conditions because you are not awaiting it? Honestly that's my last hope....
Brown bearOP
let me give it a shot
same issue 😦
I don't understand when I am on /cart page and I call the action
the middleware shows this
POST /de/cart 303 in 575ms
but when I am on login page it shows this
/[lang]/cart
but it nevers shows a POST
it looks like it is not calling it at all
Login page is a server component?
Brown bearOP
the login page itself yes but I have the SignInFormContainer() which is marked with 'use client'
and here I am making the call
I don't know if the caching is doign something here
POST requests aren’t cached and even if you were just “fetching” you need to wrap functions in unstable_cache
Brown bearOP
hmm yeah, I doesn't make sense
If you wanna see if the action is being called it it isn’t at all add a console log inside it and check the server console
Brown bearOP
yes I added logs but they don't show
this is the error I get
Found this, maybe helps.. hopefully does that’s all I can do 😭
Brown bearOP
nothing seems promising but gotta try
Also, try marking the page as “dynamic” with export const dynamic = “force-dynamic”, if the pages require auth they’re meant to be dynamic anyway
Brown bearOP
thnx u very much on your side
Brown bearOP
it's an issue with v14 they promised to fix in v14.3 but never released it in v15 it works
Ugh I didn’t know you were on version 14.x 😭
I should’ve asked (wouldn’t give you an answer lol but we could’ve started looking for version issues)
Brown bearOP
I think the whole issue is in the middleware
and. specifically with my middleware configuration
motherfckin middleware fault
Hey they recently committed to listen to ideas to improve the middleware API.
Btw mark the solution for the original question so people can find it easy;)
Brown bearOP
man
it was my dumbass
who is copying from chatgpt and now it cost me whole night figuring out
the reason why it wasn't working was because in middleware
I was checking if I have the token to now allow the route to be visited
when the loginAction finished it was setting the token in cookie and when the otherAction was being called in the login page the middleware didn't allow it
😭
I am just animal
@Brown bear motherfckin middleware fault
Lol that happens, poor middleware it wasn’t its fault after all:C
@LuisLl Lol that happens, poor middleware it wasn’t its fault after all:C
Brown bearOP
yeah lmao, I was so mad thinking this is a nextjs issue I cursed at the framework 😂
I wish this is handled tho and a better error message is provided
They improved the error messages in the recent release
And the feedback UI
Brown bearOP
yes I checked but for this particular issue it was the same error