def update
if @user.save
redirect_to root_path, notice: "success!"
else
render :edit, alert: "failed..."
end
end
このnotice, alertの仕組み(flash)をgolangで書いているwebappでも使いたい。
そして標準パッケージだけで完結させたい。
ということで実装してみた。
flashにメッセージを登録する場所(handler)
こちらは実際のコードを簡易化させています。(ログインのセッション処理など省略)
// handler/register.go
func register(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
input := &input.Register{
Name: r.FormValue("name"),
Email: r.FormValue("email"),
Password: r.FormValue("password"),
}
user, err := usecase.Register(input)
if err != nil {
flash.SetAlert(w, e.Error()) // 登録
http.Redirect(w, r, "/", http.StatusBadRequest)
return
}
flash.SetNotice(w, "success!!") // 登録
http.Redirect(w, r, "/", http.StatusFound)
}
実際のflash実装
やっていることはシンプルで、
- リクエストのたびにcookieからflashの情報を削除
- これをhandlerのwrapperとして実装するのがポイント
- handlerから受け取ったメッセージをcookieにセット
の2つ.
// flash.go
package flash
import "net/http"
// 受け取ったhandlerを処理する前に前回のレスポンスでセットしたflashをクリアするwrapper.
func ClearFlashMessage(h http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
clearCookie(w, "alert")
clearCookie(w, "notice")
h(w, r)
})
}
func clearCookie(w http.ResponseWriter, name string) {
c := &http.Cookie{
Name: name,
Value: "",
Path: "/",
HttpOnly: true,
MaxAge: -1, // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
}
http.SetCookie(w, c)
}
type Flash struct {
Alert string
HasAlert bool
Notice string
HasNotice bool
}
func NewFlashFromCookie(r *http.Request) *Flash {
var alertMsg string
alert, _ := r.Cookie("alert")
if alert != nil {
alertMsg = alert.Value
}
var noticeMsg string
notice, _ := r.Cookie("notice")
if notice != nil {
noticeMsg = notice.Value
}
return newFlash(alertMsg, noticeMsg)
}
func newFlash(alert, notice string) *Flash {
return &Flash{
Alert: alert,
HasAlert: len(alert) > 0,
Notice: notice,
HasNotice: len(notice) > 0,
}
}
func SetAlert(w http.ResponseWriter, alert string) {
setFlash(w, alert, "alert")
}
func SetNotice(w http.ResponseWriter, notice string) {
setFlash(w, notice, "notice")
}
func setFlash(w http.ResponseWriter, msg string, name string) {
c := &http.Cookie{
Name: name,
Value: msg,
Path: "/",
HttpOnly: true,
MaxAge: 100,
}
http.SetCookie(w, c)
}