Reputation: 241
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
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
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