RemixでCookieから値を取得することができない

# はじめに

Remixでアプリケーションを作っているのですが、Cookie周りで苦戦したのでまとめていきます

# 問題

RemixはステートではなくCookieで値を保持しておくことが多いため、バックエンドサーバーから送られてきたセッションIDをログイン時にCookieに保存して、トップページに遷移するようなコードを書きました

```ts:login.tsx

export const action = async ({ request }: ActionFunctionArgs) => {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const response = await fetch(`${process.env.BE_HOST}/api/users/login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ user: { email, password } }),
  });
  if (response.ok) {
    const sessionData = response.headers.get("Set-Cookie");
    if (!sessionData) {
      return json({ error: "ログインに失敗しました" }, { status: 500 });
    }
    const sessionId = sessionData.split("_session_id=")[1].split(";")[0];

    return redirect("/", {
      headers: {
        "Set-Cookie": sessionId
      },
    });
  } else {
    return json(
      { error: "メールアドレスまたはパスワードが不正です" },
      { status: 401 }
    );
  }
};
```

そしてログイン時にすでにログイン済みかを以下の関数でチェックするようにしました

```ts
export async function requireUserSession(request: Request) {
  const sessionId = await getUserFromSession(request);
  console.log(`sessionId: ${sessionId}`);

  if (!sessionId) {
    throw redirect("/login");
  }

  return sessionId;
}

export async function getUserFromSession(request: Request) {
  const cookie = request.headers.get("Cookie");
  const sessionId = cookie?.split("_session_id=")[1];

  if (!sessionId) {
    return null;
  }

  return sessionId;
}
```

しかしこの方法でやるとローカルではうまく行くのですが、ステージング環境にデプロイした時になぜかCookieに保存がされずに、sessionIdが`null`となってしまいログインページにリダイレクトされてしまいました

# 解決方法


https://remix.run/docs/en/main/utils/cookies

ドキュメント通りに実装していくことで解決しました

```ts:login.tsx
export const action = async ({ request }: ActionFunctionArgs) => {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const response = await fetch(`${process.env.BE_HOST}/api/users/login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ user: { email, password } }),
  });
  if (response.ok) {
    const sessionData = response.headers.get("Set-Cookie");
    if (!sessionData) {
      return json({ error: "ログインに失敗しました" }, { status: 500 });
    }

    const cookieHeader = request.headers.get("Cookie");
    const cookie = (await userPrefs.parse(cookieHeader)) || {};
    cookie.epSessionId = sessionData.split("_session_id=")[1].split(";")[0];

    return redirect("/", {
      headers: {
        "Set-Cookie": await userPrefs.serialize(cookie),
      },
    });
  } else {
    return json(
      { error: "メールアドレスまたはパスワードが不正です" },
      { status: 401 }
    );
  }
};
```

```ts
import { createCookie } from "@remix-run/node";
import { redirect } from "@remix-run/react";

export async function requireUserSession(request: Request) {
  const sessionId = await getUserFromSession(request);
  console.log(`sessionId: ${sessionId}`);

  if (!sessionId) {
    throw redirect("/login");
  }

  return sessionId;
}

export const userPrefs = createCookie("user-prefs", {
  maxAge: 604_800,
});

export async function getUserFromSession(request: Request) {
  const cookieHeader = request.headers.get("Cookie");
  const cookie = (await userPrefs.parse(cookieHeader)) || {};
  const sessionId = cookie.epSessionId;

  if (!sessionId) {
    return null;
  }

  return sessionId;
}
```

# おわりに

私は以下のZennも参考にしたのですが、なぜかデプロイするとCookieが保持できていませんでした

https://zenn.dev/aono/articles/67e97342495ac6

結果的には解決できたのでハードルを超えられたので良かったです

# 参考

https://remix.run/docs/en/main/utils/cookies

https://zenn.dev/aono/articles/67e97342495ac6