- 投稿日:2020-10-19T23:19:53+09:00
GORMでマイグレーションする際の覚書
はじめに
struct
でモデル定義、AutoMigrate
でマイグレーションを実行、といった辺りで少し調べた部分をメモしておきます。IDにUUIDを使用するには
UUIDの自動生成をライブラリに任せつつ、テストやシードデータの投入時には固定のUUIDも指定できるようにしたかったため、以下のように対応しました。
まずはstructでのモデルの定義
package model type User struct { ID string `gorm:"primaryKey;size:255;default:uuid_generate_v4()" json:"id"` ... }上記
uuid_generate_v4()
を利用するために、AutoMigrate(&User{})
する前にpostgresに拡張機能uuid-ossp
をインストールdb, err = gorm.Open("postgres", fmt.Sprintf( "host=%s port=%s user=%s password=%s dbname=%s", host, port, user, password, dbname, )) if err != nil { panic(err) } db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`) result := db.AutoMigrate(&model.User{}) ...Postgresのenum型を使用するには
structのタグで型を指定
type User struct { Role string `gorm:"type:role_enum;default:'user'" json:"role"` ... }
AutoMigrate
する前にpostgresに型の定義を追加db.Exec(` DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'role_enum') THEN create type role_enum AS ENUM ('admin', 'editor', 'user'); END IF; END $$; `) result := db.AutoMigrate(&model.User{}) ...まとめ
GORMのマイグレーションまわりに関してのメモでした。また他にあれば追記していきます。
- 投稿日:2020-10-19T14:21:59+09:00
【Golang】testing で関数のエラー終了 "os.Exit(1)" をテストする
Go 言語(以下 golang)の
testing
で関数がos.Exit(1)
するのをテストしたい。「"golang" test "os.Exit(1)"」でググってもドンピシャの記事がなかったので、自分のググラビリティとして。
TL; DR
処理を別プロセスで実行して、ステータスを取得する。
テスト自体には、環境変数でフラグが立っていた場合のみ該当する関数を実行するように分岐させておく。TS; DR
Golang のユニットテスト機能
testing
でos.Exit(1)
する関数の動作テストをしたかったのです。Golang には
try
-catch
-finally
といった例外処理がないため、エラーをthrow
するのではなく、error
インターフェースを実装して戻り値として返すのが一般的なようです。
- Go言語のエラーハンドリングについて @ Qiita
- 例外(exception)がない理由は? | FAQ @ Golang.jp
しかし、単純に
os.Exit(1)
する関数の動作テストをするために実装するのかぁ、と思っていたところ中国の掲示板から「2014 年の Google I/O で言及されている」との情報を得ました。「別プロセスで実行させる」という目から鱗の方法でした。もっとシンプルにテストができる方法があれば教えてください。勉強して記事を更新いたします。
シンプルなサンプル
下記は
sayonara()
がステータス 1(os.Exit(1)
)で終了することをテストするサンプルです。main.gopackage main import ( "fmt" "os" ) // この関数の動作テストがしたい func sayonara() { fmt.Println("Sayonara!") os.Exit(1) } func main() { Sayonara() }main_test.gopackage main import ( "os" "os/exec" "testing" ) func Test_sayonara(t *testing.T) { // 環境変数 "FLAG_RUN_SAYONARA" のフラグが立っていた場合に sayonara() を実行させる if os.Getenv("FLAG_RUN_SAYONARA") == "1" { sayonara() return } // 外部プロセスの実行コマンド設定 var cmd = exec.Command(os.Args[0], "-test.run=Test_sayonara") // 外部プロセス実行時の環境変数をセット(FLAG_RUN_SAYONARA -> 1) cmd.Env = append(os.Environ(), "FLAG_RUN_SAYONARA=1") // 外部プロセスの外部実行 var err = cmd.Run() // 外部プロセスの実行結果取得。エラーの場合は正常終了 if e, ok := err.(*exec.ExitError); ok && !e.Success() { return } // 実行ステータスがエラーでない(ステータスが 0)の場合は Fail させる t.Fatalf("process ran with err %v, want exit status 1", err) }
- オンラインで動作をみる @ The Go Playground
参考文献
- Go言語のエラーハンドリングについて @ Qiita
- 例外(exception)がない理由は? | FAQ @ Golang.jp
- testing - 如何在Go中测试os.exit场景 @ coder.work (这是非常有用的信息。非常感谢你。)
- "Testing Techniques" P.23 by Andrew Gerrand @ Google I/O 2014
- 投稿日:2020-10-19T14:21:59+09:00
【Golang】testing で、関数のエラー終了 "os.Exit(1)" をテストする
Go 言語(以下 golang)の
testing
で関数がos.Exit(1)
するのをテストしたい。「"golang" test "os.Exit(1)"」でググってもドンピシャの記事がなかったので、自分のググラビリティとして。
TL; DR
処理を別プロセスで実行して、ステータスを取得する。
テスト自体には、環境変数でフラグが立っていた場合のみ該当する関数を実行するように分岐させておく。
- オンラインでサンプルの動作をみる @ The Go Playground
ただし、カバレッジには反映されないので注意。カバレッジを 100% にするには、いささか工夫が必要です。(記事反映準備中)
- オンラインでカバレッジ 100% のサンプルをみる @ paiza.IO
TS; DR
Golang のユニットテスト機能
testing
でos.Exit(1)
する関数の動作テストをしたかったのです。Golang には
try
-catch
-finally
といった例外処理がないため、エラーをthrow
するのではなく、error
インターフェースを実装して戻り値として返すのが一般的なようです。
- Go言語のエラーハンドリングについて @ Qiita
- 例外(exception)がない理由は? | FAQ @ Golang.jp
しかし、単純に
os.Exit(1)
する関数の動作テストをするために実装するのかぁ、と思っていたところ中国の掲示板から「2014 年の Google I/O で言及されている」との情報を得ました。「別プロセスで実行させる」という目から鱗の方法でした。もっとシンプルにテストができる方法があれば教えてください。勉強して記事を更新いたします。
シンプルなサンプル
下記は
sayonara()
がステータス 1(os.Exit(1)
)で終了することをテストするサンプルです。main.gopackage main import ( "fmt" "os" ) // この関数の動作テストがしたい func sayonara() { fmt.Println("Sayonara!") os.Exit(1) } func main() { sayonara() }main_test.gopackage main import ( "os" "os/exec" "testing" ) func Test_sayonara(t *testing.T) { // 環境変数 "FLAG_RUN_SAYONARA" のフラグが立っていた場合に sayonara() を実行させる if os.Getenv("FLAG_RUN_SAYONARA") == "1" { sayonara() return } // 外部プロセスの実行コマンド設定 var cmd = exec.Command(os.Args[0], "-test.run=Test_sayonara") // 外部プロセス実行時の環境変数をセット(FLAG_RUN_SAYONARA -> 1) cmd.Env = append(os.Environ(), "FLAG_RUN_SAYONARA=1") // 外部プロセスの外部実行 var err = cmd.Run() // 外部プロセスの実行結果取得。エラーの場合は正常終了 if e, ok := err.(*exec.ExitError); ok && !e.Success() { return } // 実行ステータスがエラーでない(ステータスが 0)の場合は Fail させる t.Fatalf("process ran with err %v, want exit status 1", err) }
- オンラインで動作をみる @ The Go Playground
問題は、この方法だとプロセスが別なためコードカバレッジに反映されないので網羅したことにならないんですよね。
コメントを元に、カバレッジを 100% 網羅したサンプルは出来たのですが、
やる気が帰って来ていないので準備中なので記事への反映はお待ちください。適宜、更新いたします。
- カバレッジ 100% のサンプルをオンラインでみる @ paiza.IO
参考文献
- Go言語のエラーハンドリングについて @ Qiita
- 例外(exception)がない理由は? | FAQ @ Golang.jp
- testing - 如何在Go中测试os.exit场景 @ coder.work (这是非常有用的信息。非常感谢你。)
- "Testing Techniques" P.23 by Andrew Gerrand @ Google I/O 2014
- 投稿日:2020-10-19T08:14:21+09:00
タグ1つでブログを収益化できる投げ銭サービスを支える技術
はじめに
こちらに今回の開発を通して一番重要だと感じていることを記事にしました。
【個人開発】開発プロセスが何より大事だった ~ タグ1つでブログを収益化できる投げ銭サービス ~先日 plog というサービスをリリースしました。
YouTube に使い方など載せています。
最近noteやzennなど、有料記事によるブログ収益化サービスが流行っています。
とても良いサービスですが、プラットフォームに依存した収益ですし、何より手数料が高いな・・・と思っていました。そこで、プラットフォームに依存しない有料ブログの収益化サービスを思いつき、先日α版をローンチしました。
plogのシステム設計
全体のざっくりとしたイメージではこのような形になっています。
①100円の決済フォームくれ
いくらのどんな記事のためのフォームが欲しいですよ!とクライアントからサーバへリクエスト②情報を元に100円の決済フォームくれ
POST /v1/payment_intents
stripeのapiを使用し、決済フォームをリクエスト③決済フォームの元を返却
PaymentIntentsの情報が返却される④ClientSecretを返却
返却されたpaymentintentから、ClientSecret取得しClientに返却⑤有料記事を購入
ユーザにクレジットカード情報などを入力してもらい、決済ボタンをおす⑥決済実施
ユーザが有料記事を購入ボタンをおしたら、stripe.confirmCardPayment(clientSecret,data?,options?)
stripe.jsの関数を使用し、Stripeに決済実施リクエスト。⑦Webhookで決済完了したら情報格納
Stripeのwebhookを使い、決済が正常に完了した場合に、正常に決済した情報や諸々をDBに格納し完了。といった流れです。
MVPを意識して作ったため、とても簡単な作りになっています。
ここからが主題で、plogではStripeを使用しサービスを運営しています。
Stripeを使うにあたって何点か戸惑った箇所などがあったので、頭の整理も兼ねてまとめていきます。対象読者
Stripeを使おうとしているけど、Charges Checkout PaymentIntentsどれ使えやいいねん!って思ってる人
Stripeの決済パターン
結果公式のStripe APIを見ればいい話ですが、
docsっていきなり読むにはちょっと重いので全体感がわかるようなイメージとしてまとめます。まず決済のパターンは大きく分けてこの3つで、用途に適した手段を使えば良いです。
- Charges API
- Stripe Checkout
- Payment Intents API
Charges API
https://stripe.com/docs/payments/charges-api
Charges APIは、カード認証の銀行リクエストを処理しない古い支払いAPIです。代わりに、新しいペイメントAPIと統合をお試しください。
PaymentIntentsの前進みたいな立ち位置だったのかな?
まず公式でもこのように言ってるので、使わない方が良さそうです。簡単に使ってみたところ、ほぼほぼやりたいことはPaymentIntentsで出来るので、chargeを使おうとしているなら、
PaymentIntentsを使っちゃうで良いと思います。
※ 一部まだPaymentIntentsでは対応していなユースケースもあるそうなので、あくまでイメージとして捉えてください。Stripe Checkout
Stripeが提供しているほぼ形が決まったテンプレートを使用して決済したい場合に使えそうです。
ただ、決済画面はStripe側にリダイレクトされてしまうため、決済時に何か特別に処理をしたいなどは難しそうな印象。あと、Stripeに必要なデータ以外も入力して欲しい時などは、自分で決済フォームを作った方が楽なので、
PaymentIntentsを使った方が便利そうです。PaymentIntents API
こんな感じの自分で決済フォームをカスタマイズして作りたい場合は、PaymentIntentsを使うのが良さそうです。
↓私はこちらのdocsをみながら実装するのが一番近道になりました。
https://stripe.com/docs/payments/accept-a-payment?integration=elementsWebhook
後の方に知って、とても使えたのが、Stripeが提供するWebhookです。
決済が完了した時や、決済が失敗した時など、
いろんなトリガーを指定して、実装を組み込むことが出来ます。plogの場合は、決済が完了した時に、購入者情報などをDBに永続化するようにしています。
最後に
plogもローコードツールの類ですが、
Stripeのように、決済という難易度の高く面倒な箇所をローコードで簡単に導入することが出来るのは、
開発者にとってとてもありがたかったです。また、こちらに今回の開発を通して一番重要だと感じていることを記事にしました。
【個人開発】開発プロセスが何より大事だった ~ タグ1つでブログを収益化できる投げ銭サービス ~タグ1つでブログを収益化できる投げ銭サービス plogでした。
https://plog.cash/