Connor V
Connor V

Reputation: 241

Remix - Can't 'Set-Cookie' anywhere except in the response from the loader of the current route

I have the world's most basic remix app setup to try to figure out createStorageSessionCookies and it seems like they can only be set in the loader of the UI route that is calling the API.

Example:

If I try to set the cookie anywhere else except for the return from loader in the Index UI route, it doesn't work. If I call the testApi and try to return a response that sets the cookie, doesn't work. If I create a separate function that is called from the loader and that function returns the result of an API call and tries to set the cookie, doesn't work. It literally only works if I set the cookie in the response of the loader.

Example Index route where it works

export const loader: LoaderFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisworks');
    return json(
        { status: 'this works' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

This won't work

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisdoesntwork');
    return json(
        { status: 'this doesnt work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

export const loader: LoaderFunction = async ({ request }) => {
    const failFunc = await setCookie(request)
    return failFunc.json()
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

Also won't work trying to set them from an API route (app/routes/api/setCookie.tsx called from the loader or from a button - neither work)

export let loader: LoaderFunction = () => redirect('/');

export let action: ActionFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return json(
        { status: 'does not work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

Upvotes: 4

Views: 9708

Answers (2)

rphlmr
rphlmr

Reputation: 918

When you extract some code in function that return remix Response, json etc, you can't just return a json(...). You have to throw it instead ;)

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thishouldwork');
    throw json(
        { status: 'this should work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

Check the doc example here : https://remix.run/docs/en/v1/api/conventions#throwing-responses-in-loaders

And for your last snippet, I would not create a loader that just redirect. Because after an action Remix triggers loader. Maybe it create an unexpected behaviour.

If you want to redirect after this action, submit a form from your button like that :

<Form method="post" action="/api/setCookie">
 <button name="redirectTo" type="submit" value="/a-path-to-redirect" />
</Form>
export let action: ActionFunction = async ({ request }) => {
    const form = await request.formData();
    const redirectTo = formData.get("redirectTo");

    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return redirect(
        redirectTo,
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

Upvotes: 1

Warmpigman
Warmpigman

Reputation: 11

Why are you calling .json() on the response from the setCookie function, when you just return json() normally. https://remix.run/docs/en/v1/api/remix#json

Upvotes: 1

Related Questions