コンテンツにスキップ

プリセットの選択を変える

プリセットは 10 個の答えに名前を付けたもので、そのどれもが依然として「答え」です。 このページは、そのうちのひとつが間違っていたとわかったときに読むものです。

たいていは 1 コマンドで済みます。断った機能は pw add が入れ、 pw init と同じウィザードが走って、書き込む前に対象ファイルを全部見せます。例外は 2 つ。データベースエンジンは他のどの答えより多くのファイルに触りますし、プロジェクトの 種類はそもそも変換できません。

データベースエンジンを切り替える

Section titled “データベースエンジンを切り替える”

website-login が SQLite を選ぶのは、アプリケーションのほかに起動するものが何もない からです。最初の 1 週間はそれが正しく、すでに Postgres を運用している配備先にとっては 正しくありません。

やるなら、意味のある場所でマイグレーションを走らせる前です。ここでデータは変換されません。 変わるのは生成する内容と接続先で、古いデータベースの行は古いデータベースに残ります。

変わるものは 5 つ、まとめて変わります。

popcornweb.tomlproject.database pw generate はこの値を見て、.pw.sql を どの方言のプレースホルダにコンパイルするかを決めます。変えたら再生成しないと、型付き クエリ関数は前の方言を吐き続けます。

popcornweb.toml
[project]
database = "sqlite"

config.dev.toml の DSN。 ほかの環境ファイルにも同じものがあります。

config.dev.toml
[middleware.rdb]
dsn = "sqlite://myapp.db"

main.go のドライバ import。 SQLite を含むすべてのエンジンが明示的な選択です。 使うドライバだけをブランク import するため、不要なドライバはバイナリに入りません。

cmd/myapp/main.go
import (
_ "github.com/shibukaway/popcornweb/database/sqlite"
)

devbox.json の開発サーバー。 SQLite にはそもそも該当するものがありません。

{ "packages": ["go@latest", "git@latest"] }

マイグレーション。手で書き換えます。 ここが実際に時間を食う部分で、道具はありません。 Popcorn Web は .pw.sql をひとつの方言にコンパイルするだけで、方言のあいだを翻訳 しません。キーをひとつ変えたからといって AUTOINCREMENTSERIAL になることはなく、 datetime('now')NOW() になることもない。migrations/ の DDL と、queries/ の 移植性のない式は、ファイルを開いて書き直す対象です。

ログインのあるプロジェクトでは、さらに 2 つ変わります。どちらも気づきにくい部分です。

フレームワーク自身のマイグレーションも古い方言のままです。 ログインのある プロジェクトは ..._init_popcornweb_auth.sql を持ち、rdb セッションバックエンドなら ..._init_popcornweb_session.sql も持ちます。これらはあなたの DDL ではなくフレームワークの DDL で(BLOB に対する BYTEAWITHOUT ROWID に対する何もなし)、再発行するコマンドは ありません。移行先のエンジンで同じ回答の使い捨てプロジェクトを作り、そのファイルを 持ってくるのが実際的な手順です。

Terminal window
pw init --yes --db=postgres --auth=oidc --session=redis --router=discovered /tmp/probe
cp /tmp/probe/migrations/*_init_popcornweb_*.sql migrations/

バージョン番号が異なる場合は、現在の番号を維持してください。置き換えるのは中身だけです。

認証状態のストアはエンジンごとに別パッケージです。 main.goauthstate/sqlite をリンクしていて、あるエンジンの DDL を別のエンジンは読めません。

cmd/myapp/main.go
import (
// もとは authstate/sqlite。
_ "github.com/shibukawa/popcornweb/authstate/postgres"
)

いちばん安く切り替えられるのが、手元以外でマイグレーションを走らせる前だというのは これが理由です。4 週間動いているプロジェクトには移すスキーマがそれだけ増えていますし、 本番が動いていれば移すデータもあります。後者はこのページの範囲外です。

書き換えたら、生成と適用をやり直します。

Terminal window
pw generate
pw migrate up

DSN の書式と接続グループは リレーショナルデータベースに全部あります。

セッションバックエンドを切り替える

Section titled “セッションバックエンドを切り替える”

website-login はセッションを Redis に置きます。別のバックエンドへ移すのは配備の変更で、 アプリケーションの変更ではありません。ハンドラから見ればどのバックエンドも同じなので、 自分で書いたコードは変わりません。

session.backend を変え、登録するブランク import を差し替え、新しいバックエンドに マイグレーションがあれば適用します。

config.dev.toml
[session]
backend = "rdb"
rdb.source = "middleware"
cmd/myapp/main.go
import (
// もとは sessionstore/redis。
_ "github.com/shibukawa/popcornweb/sessionstore/sqlite"
)

rdb バックエンドはフレームワークが持つマイグレーションを伴うので、切り替えたあとに pw migrate up を実行します。cookie バックエンドはストレージも import も持たず、 最初の起動前に環境変数 SESSION_COOKIE_SECRET が要ります。Redis からの移行では、 devbox.json に誰も使わない Valkey パッケージが残ります。消しても放置してもかまいません。 使われない開発サービスの代償は起動時間だけです。

失効、サイズ、期限、運用コストの違いは、5 つのバックエンドを並べた セッションストレージで比較できます。

単純サイトのプリセットは 2 つとも認証を断ります。入れるのは 1 コマンドです。

Terminal window
pw add auth

pw init が聞いたはずの質問をウィザードが聞き、確認画面が書き込み前に全ファイルを 並べます。認証処理中のレコード、アカウント、許可リストにはサーバーストアが必要です。 既存のリレーショナルデータベース、DynamoDB、Firestore のいずれかを利用でき、どれも なければ先にリレーショナルデータベース機能が追加されます。

何が入るかは認証の組み込みが扱います。

2 つのルーターはひとつの mux 上で共存するので、これは持っていないほうを追加する操作で、 持っているほうを置き換える操作ではありません。

Terminal window
pw add discovered # または: pw add registered

結果として両方のツリーができます。これはサポートされた形です。handlers/ に API、 pages/ にサイトというのは普通の Popcorn Web プロジェクトです。ただ、追加ではなく 移行のつもりだったなら、元のツリーを消すのは誰も代わりにやってくれない手作業です。

ページツリーが登録に対して何を買うのかは 探索型ルーティングにあります。

api-server は最初のコマンドで起動し、存在しない issuer に対してトークンを検証します。 字面ほど妙な話ではありません。pw dev の下ではトークンは検証されずに読まれるので、 config.dev.toml に書かれた issuer に何かを取りに行くことは一度もありません。書いてあるのは、 このモードが issuer なしでは起動を拒否するからで、その規則自体はどの環境でも正しいものです。

つまり手元ではすぐ動き、どこにもデプロイできないプロジェクトが手に入ります。仕上げるとは、 本物の issuer を名指しすることです。

# config.dev.toml — 両方を置き換えるか、AUTH_JWT_ISSUER と AUTH_JWT_AUDIENCE で与える
[auth.jwt]
issuer = "https://your-idp.example.com"
audience = ["your-api"]
allow_loopback_http = false

それまでのあいだ、サインインする curlconfig.dev.toml のコメントにあります。手書きの トークンに必ず要るクレームは isssub の 2 つです。issuer が何を名乗っているかは 誰も見ませんが、API から見えるアカウントはこの 2 つから導出されるので、どちらかを変えることが 「別人として開発する」方法になります。

本物の issuer ができたら dev.trust_unverified_tokens は消してください。忘れても大丈夫です。 開発用タグなしでビルドしたバイナリはこのフィールドがあると起動を拒否しますし、 APP_ENV=stgprod でも同じ設定は拒否されます。

次に admission を決めます。スキャフォールドが選ぶのは authenticated で、issuer が 検証した全員を通します。issuer を自分で管理していて、そこが発行する相手がこの API を 使ってよい人だけなら、これが正解です。共有の issuer なら claim にして、テナントや 部門を名指しします。

[auth.jwt]
admission = "claim"
claim.path = "org"
claim.values = ["acme"]

失効リストを有効にするか admission を registered にすると、サーバー側の状態が必要に なります。認証バックエンドに rdbdynamofirestore のいずれかを選び、対応する 機能を先に追加してください。rdb なら popcornweb_revoked_token のスキーマを作るため pw migrate up を実行します。ほかのストアでは、それぞれのデプロイ手順に従います。

できません。パッケージとアプリケーションはどちらの向きにも変換できず、その違いは 切り替えられる答えではないからです。パッケージは生成された Go をコミットし、 エントリポイントを持たず、環境設定も持ちません。それを利用する側のプロジェクトには、 生成することも起動することも設定することもできないためです。

もう一方の種類を作って、ソースを移してください。1〜2 ファイルを超える規模なら変換より 安く済みますし、途中まで進んでから「変換より作り直しのほうが安かった」と気づくよりは ずっと安く済みます。

上の節のうち 3 つが自分のプロジェクトに当てはまるなら、出発点のプリセットが違っていました。 pw init は 1 分かからず新しいディレクトリを作ります。自分で書いたハンドラとテンプレートを 正しくスキャフォールドされたプロジェクトへ移すほうが、設定と import とマイグレーションを 1 ファイルずつ変換していくより、たいていは手数が少なく、そして常にリスクが小さい。

変換のほうを選ぶ理由は、移すこと自体が高くつくくらい書いてしまった場合です。その分岐点は、 感覚より遅く来ます。