gorilla/schemaにデフォルトタグが追加されたので書き留める
自分が使い出した頃には実装はされていたが、リリースはされておらず悶々としていた。
とりあえず何かと今後も使う気がするので、自分宛にメモすることにする。
gorilla/schemaとは
Package gorilla/schema converts structs to and from form values.
リクエストのPOSTの値やパスパラメータを解析し、構造体にデコードしてくれるパッケージ
パスパラメータのデフォルト値を設定できるようになった
具体的に実装の部分を見ていく
ざっくり処理の流れ
107行目から見ていく。
構造体のFieldをループし、
110行目からフィールドの種類が構造体でデフォルト値が設定されていない場合
その構造体を再帰的にsetDefaults
メソッドを実行します。
ポインター型の場合isPointerToStruct
メソッドでゼロ値ではなく、ポインター型で構造体でかつデフォルト値が設定されていない場合再帰的にsetDefaults
メソッドを実行します。
116行目でデフォルト値が設定されていて、Requiredが設定されている場合エラーを返しています。
118.119でデフォルト値が設定されていてフィールドの値がゼロでRequiredがついていない場合中の処理が走る
119で構造体の場合エラーを返しています。
121-137でスライス型の場合|
で値を区切り、map
型のbuildinConverters
で型がサポートされているかチェックする。
チェック後に|
で区切ったvals
をループし、各val
をbuiltinConverters
からフィールドのタイプをキにメソッドを取り出し、val
を引数に型を検証しています。
現状の実装では要素の型がフィールドの型と違った場合はそのデフォルト値を無視するようになっているそうです。
138-148
フィールド型ポインターで構造体かスライスの場合エラーを返す
値をコンバートしてコンバートに成功すればデフォルト値をセット
それ以外のケースはbuiltinConverter
で値を検証し、成功すれば値をセット
具体例
クエリパラメータをデコードし、Nameフィールドを返してます。
var decoder = schema.NewDecoder()
type Person struct {
Name string `schema:"name,default:test1"`
Names []string `schema:"names,default:test1|test2"``
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
var d = Person{}
if err := decoder.Decode(&d, r.URL.Query()); err != nil {
log.Fatal("Error while decoding:", err)
}
fmt.Fprintf(w, d.Name)
})
http.ListenAndServe(":8080", nil)
}
カスタムスキーマを作ってみる。
Validate
メソッドが引数のdst
に定義されていれば実行します。
カスタムで何かしらの処理を追加したいときに使う。
func main() {
var decoder = schema.NewDecoder()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
var d = Person{}
if err := decode(decoder, &d, r.URL.Query()); err != nil {
log.Fatal("Error while decoding:", err)
}
fmt.Fprintf(w, d.Name, d.Num)
})
http.ListenAndServe(":8080", nil)
}
func decode(decoder *schema.Decoder, dst interface{}, src map[string][]string) error {
if err := decoder.Decode(&dst, src); err != nil {
log.Fatal("Error while decoding:", err)
}
d, ok := dst.(interface {
Validate() error
})
if !ok {
return nil
}
return d.Validate()
}
Discussion