web-dev-qa-db-ja.com

golangのx-www-form-urlencodingをマーシャルするパッケージはありますか

私は、jsonまたはxmlでそれを行うことができる方法と同様に、x-www-form-urlencodingの内外でマーシャリングしたいと考えています。これを行うための既存のパッケージはありますか、または存在しない場合に自分で実装する方法に関するドキュメントはありますか?

28
placeybordeaux

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日更新:

  • gorilla/schemaは、最もサポートされているmap-to-structパッケージの1つとして私の選択です。POSTフォーム値が一般的なユースケースです。
  • goji/param もかなりしっかりしており、同じ機能を多数備えています。
  • mholt/binding は、もう少し複雑なAPIの(IMO)費用で、もう少し機能が詰め込まれています。

私は数年前からゴリラ/スキーマを使用しており、大きな問題はありませんでした。私はそれを vala と組み合わせて使用​​して、DBに到達する前に入力を検証します(nilではなく、短すぎたり、長すぎたりしない)。

15
elithrar

私はちょうど https://github.com/ajg/form を見つけました。これはまさに私が探していたものです。厳密にデコードする場合は https://github.com/gorilla/schema 、厳密にエンコードする場合は https://github.com/google/go-querystring もあります。

6
placeybordeaux

https://github.com/google/go-querystring は適切ですが、マップ(およびマップのスライス)をサポートしていません。

マップのサポートのために https://github.com/drewlesueur/querystring を開始しました。 (まだ構造体をサポートしていませんが、プルリクエストは歓迎します)。

2
Drew LeSueur

"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()
    }
    
1
pasztorpisti