Vercelでsessionを使う（Python Flask）

# VercelでAPIを作成

Reactを扱うAIの[v0](https://v0.dev/)にはまり[BlueSkyの画像検索サイト](https://bluesky-media-gallery.vercel.app/)を作っていました。
実行環境としてv0の開発元のVercelにフロントエンド、BlueSkyのデータを取得するAPI共にデプロイしようとしました。（APIは別プロジェクトとしてPythonでサーバレスファンクションとして作成しました）

で困ったのはFlaskのsessionに保存ができないことです。このサンプルを起動して振り出されたURLにアクセスすればrequest_countが増えるはずですがjavascriptからfetchで呼び出すと増えないまま。sessionが扱えてないことがわかりました。

```python:server.py（session確認サンプル）
from flask import Flask, jsonify, session
from flask_cors import CORS
from datetime import timedelta

app = Flask(__name__)
app.secret_key = "abcde"
app.permanent_session_lifetime = timedelta(minutes=30)

CORS(app, supports_credentials=True)

@app.route("/", methods=["GET"])
def return_media():

    if not session.get("request_count"):
        session["request_count"] = 1
    else:
        session["request_count"] += 1

    return_data = {"request_count" : session["request_count"]}

    return jsonify(return_data)

if __name__ == "__main__":
    app.debug = True
    app.run(host="0.0.0.0", port=5000)
```

<br>

※以下のように直接アクセスすればうまく行くのですが、ブラウザからfetchで呼び出すとrequest_countは1のまま。

![スクリーンショット 2025-02-27 222515.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3549938/c6519040-333b-4257-8068-a0c7a1b59365.png)

<br>

これを解消すべく「Vercel session」検索してみると以下の記事が出てきました。

https://zenn.dev/mochinozenn/articles/8218f316e704e7

<br>

なるほど独自ドメインを設定すればいいのか…とたまたまXserverで持っていたドメインを設定。これで解決のはずがやっぱりsessionには保存できないまま。

また振出しに戻りGoogle ChromeのDevツール（検証）とにらめっこした後、解決に到りました。結果を言いますと次のコードを加えています。


```diff_python:app.config.update追加
from flask import Flask, jsonify, session
from flask_cors import CORS
from datetime import timedelta

app = Flask(__name__)
app.secret_key = "abcde"
app.permanent_session_lifetime = timedelta(minutes=30)

+ app.config.update(
+    SESSION_COOKIE_SECURE=True,
+    SESSION_COOKIE_HTTPONLY=True,
+    SESSION_COOKIE_SAMESITE='None',
+ )

CORS(app, supports_credentials=True)

@app.route("/", methods=["GET"])
def return_media():

    if not session.get("request_count"):
        session["request_count"] = 1
    else:
        session["request_count"] += 1

    return_data = {"request_count" : session["request_count"]}

    return jsonify(return_data)

if __name__ == "__main__":
    app.debug = True
    app.run(host="0.0.0.0", port=5000)

```

<br>

このエラーがわかったのはDevツールの次の画面でした。
![スクリーンショット 2025-02-27 223928.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3549938/658d80fa-4402-434e-b2be-af4795d9d7e1.png)

<br>

Set-Cookieの項目で警告（△に！）が出ていました。これの言う通り **SESSION_COOKIE_SAMESITE='None'** にした次第です。
ただFlask公式ではこれを推奨していません。

https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/security.html

<br>

他の言語、Flask以外のフレームワークもCOOKIE_SAMESITE='None'で解決できる場合があるかと思います。
ただセキュリティ的にはまずい場合もありますのですので、利用する際にはご注意下さい。

# まとめ

警告にあるように根本的な原因はCORSのようです。CORSをちゃんと理解できていればいいのですがすぐには難しいですね…

あと今さらですがネットの記事を過信しすぎるのは良くないなと思いました。（特にニッチなケースの場合）
まぁAPIでセッションを使うというのが本来の使い方じゃないのかもしれませんが…

IT開発は言語・フレームワークなどで状況は無数に変わるので、情報の取得・発信共に気を付ける必要があるようです。

# 補足

VercelでAPIを作るには適当なフォルダ直下にvercel.json、requirements.txtを置いて、あとはapiフォルダの下にPythonのファイル（今回はserver.py）を作り、Flaskか何かでリクエストを処理できるようにします。簡単なサンプルは以下になります。

```:フォルダ構成
sample_repository
├─ api
│  └─ server.py
├─ requirements.txt
└─ vercel.json
```

```:requirements.txt
Flask==3.0.3
Flask-Cors
```


```json:vercel.json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/api/server" }
  ]
}
```


※vercel.jsonのdestinationを起動するファイル名に指定してあげて下さい

あとはこれをGitHubのリポジトリとしてプッシュしてVercelと連携するだけです