私は、jsonまたはxmlでそれを行うことができる方法と同様に、x-www-form-urlencodingの内外でマーシャリングしたいと考えています。これを行うための既存のパッケージはありますか、または存在しない場合に自分で実装する方法に関するドキュメントはありますか?
gorilla/schema は人気があり、よく管理されています。
例えば.
func FormHandler(w http.RequestWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
// handle error
}
person := new(Person) // Person being a struct type
decoder := schema.NewDecoder()
err = decoder.Decode(person, r.Form)
if err != nil {
// handle error
}
}
goforms も代替手段です。
2015年5月23日更新:
私は数年前からゴリラ/スキーマを使用しており、大きな問題はありませんでした。私はそれを vala と組み合わせて使用して、DBに到達する前に入力を検証します(nilではなく、短すぎたり、長すぎたりしない)。
私はちょうど https://github.com/ajg/form を見つけました。これはまさに私が探していたものです。厳密にデコードする場合は https://github.com/gorilla/schema 、厳密にエンコードする場合は https://github.com/google/go-querystring もあります。
https://github.com/google/go-querystring は適切ですが、マップ(およびマップのスライス)をサポートしていません。
マップのサポートのために https://github.com/drewlesueur/querystring を開始しました。 (まだ構造体をサポートしていませんが、プルリクエストは歓迎します)。
"github.com/pasztorpisti/qs"
パッケージ は、クエリ文字列およびPOST
- edフォームへ/からの構造体をマーシャリング/アンマーシャリングすることもできます。
例:
package main
import "fmt"
import "github.com/pasztorpisti/qs"
type Query struct {
Search string
Page int
PageSize int
Categories []string `qs:"category"`
}
func main() {
queryStr, err := qs.Marshal(&Query{
Search: "my search",
Page: 2,
PageSize: 50,
Categories: []string{"c1", "c2"},
})
fmt.Println("Marshal-Result:", queryStr, err)
var q Query
err = qs.Unmarshal(&q, queryStr)
fmt.Println("Unmarshal-Result:", q, err)
// Output:
// Marshal-Result: category=c1&category=c2&page=2&page_size=50&search=my+search <nil>
// Unmarshal-Result: {my search 2 50 [c1 c2]} <nil>
}
snake_case
として表示されます。このためにqs:"field_name"
をstructフィールドタグに追加する必要はありません。この動作は変更できます。bool
、[]byte
など)でもマーシャラーとアンマーシャラーを置き換え、タイプ自体を変更せずに新しいタイプのサポートを追加できるモジュラーアーキテクチャ(例:マーシャリングやアンマーシャリングの追加) time.Time
)。 ここ は例です。req
オプションをstruct fieldタグに追加して、非マーシャリング中にフィールドを必須にすることができます。これはアンマーシャリングではなく検証であり、golangライブラリは通常2つの間の分離に使用されますが、このオプションは非常に便利であることがわかりました。 req
を回避し、マーシャリング解除後にこの検証を個別に行う場合:デフォルトのnil
とほぼ同じopt
タグオプションがあります(これは、 「オプション」)。ただし、指定されたフィールドが非整列化されたクエリ文字列にない場合、nilポインターを初期化しません。このように、検証コードは、マーシャリング解除後にnilポインターを探すことにより、欠落しているフィールドを検出できます。qs
パッケージは、実際にその型のインスタンスをマーシャリングする前に、複合型(例:構造体)がマーシャリング可能かどうかを通知できます。ほとんどのマーシャラーパッケージは、指定されたタイプのインスタンスをマーシャリングした後でも、これを実行できません。ほとんどのマーシャラーは、マーシャリングされているオブジェクトをウォークし、アクセスされたサブオブジェクトのタイプのみをチェックすることにより、複雑なタイプを調べます。つまり、複合オブジェクトに空のコンテナー(ポインター、マップ、またはスライス)が含まれている場合、コンテナーの項目タイプは検査されません。コントラクトでは、qs
は、(オブジェクト自体ではなく)複雑なオブジェクトの型構造をウォークしながら、型のマーシャラーを作成します。標準の"encoding/json"
パッケージが、非整列化可能な型を含む型のオブジェクトを正常に整列化する次のコードを検討してください。
package main
import (
"encoding/json"
"fmt"
"reflect"
"github.com/pasztorpisti/qs"
)
type NonMarshalable func()
func jsonEmptyMap() {
// Since the container is empty "encoding/json" doesn't examine the type
// of its items. This results in an unexpected success.
var m = map[string]NonMarshalable{}
j, err := json.Marshal(m)
fmt.Println(string(j), err)
// Output:
// {} <nil>
}
func jsonNonEmptyMap() {
var m = map[string]NonMarshalable{
"f": func() {},
}
j, err := json.Marshal(m)
fmt.Println(string(j), err)
// Output:
// json: unsupported type: main.NonMarshalable
}
func qsEmptyMap() {
// qs.Marshal fails even if the container is empty because the first step
// of qs.Marshal fails: It can't create the marshaler object for this type.
var m = map[string]NonMarshalable{}
s, err := qs.Marshal(m)
fmt.Println(s, err)
// Output:
// error getting marshaler for map value type main.NonMarshalable :: unhandled type: main.NonMarshalable
}
func qsTypeCheck() {
// You don't even have to try to marshal an object to find out whether its
// type is marshal-friendly. You can check the type directly. By doing this
// at startup (e.g.: from init functions) you can avoid delaying runtime
// errors.
t := reflect.TypeOf((map[string]NonMarshalable)(nil))
err := qs.CheckMarshalType(t)
fmt.Println(err)
// Output:
// error getting marshaler for map value type main.NonMarshalable :: unhandled type: main.NonMarshalable
}
func main() {
jsonEmptyMap()
jsonNonEmptyMap()
qsEmptyMap()
qsTypeCheck()
}