¿Hay un paquete para entrar y salir de x-www-form-urlencoding en golang


Me gustaría entrar y salir de x-www-form-urlencoding similar a cómo se puede hacer con json o xml. ¿Existe un paquete para hacer esto, o hay algún documento sobre cómo implementar uno yo mismo si no existe?

Author: placeybordeaux, 2014-03-22

4 answers

Gorilla/schema es popular y bien mantenido:

Por ejemplo

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 es también una alternativa.

Actualización 23 de mayo 2015:

  • gorilla/schema sigue siendo mi elección como uno de los paquetes de map-to-struct más soportados, con los valores de formulario POST siendo un caso de uso común.
  • goji/param también es bastante sólido y tiene muchas de las mismas características.
  • mholt / binding está un poco más lleno de funciones a expensas (IMO) de una API un poco más compleja.

He estado usando gorilla/schema durante un par de años y no he tenido ningún problema importante con él. Lo uso junto con vala para validar entradas (no nil, demasiado corto, demasiado largo, etc.) antes de que lleguen a la base de datos.

 13
Author: elithrar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-16 02:07:39

Acabo de encontrar https://github.com/ajg/form que es exactamente lo que estaba buscando. También hay https://github.com/gorilla/schema para decodificar estrictamente y https://github.com/google/go-querystring para codificación estricta.

 6
Author: placeybordeaux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-22 18:12:14

Https://github.com/google/go-querystring es bueno, pero no soporta mapas (y porciones de mapas).

Empecé https://github.com/drewlesueur/querystring para soporte de mapas. (Todavía no admite estructuras, pero las solicitudes de extracción son bienvenidas).

 2
Author: Drew LeSueur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-25 19:21:27

El paquete "github.com/pasztorpisti/qs" también puede combinar estructuras/unmarshal a/desde cadenas de consulta y formas POST-ed.

Ejemplo:

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>
}

Posibles puntos de venta de este paquete:

  • Los nombres de los campos de estructura aparecen automáticamente como snake_case en la cadena de consulta. No es necesario agregar qs:"field_name" a la etiqueta de campo struct para esto. Este comportamiento se puede cambiar.
  • Arquitectura modular que permite reemplazar marshalers y unmarshalers incluso para tipos incorporados (como bool, []byte) y agregue soporte para nuevos tipos sin modificar el tipo en sí (por ejemplo: agregue marshaling y / o unmarshaling para time.Time). Aquí es un ejemplo.
  • Puede agregar la opción req a la etiqueta de campo de estructura para hacer que el campo sea obligatorio mientras se desmarca. Tenga en cuenta que esto es más bien la validación que unmarshaling y las bibliotecas de golang suelen ir para la separación entre los dos, pero me pareció esta opción muy útil porque se necesita a menudo, es simple y se lee bien. Para aquellos que desean evitar req y hacer esta validación por separado después de desmarcar: hay una opción de etiqueta nil que es más o menos la misma que la predeterminada opt (que significa "opcional"), excepto que no inicializa los punteros nil cuando los campos dados no están en la cadena de consulta sin marcar. De esta manera, el código del validador puede detectar los campos que faltan al buscar punteros nil después de desmarcar.
  • El paquete qs puede decir si un tipo complejo (por ejemplo: su estructura) es marshalable antes de organizar una instancia de ese tipo. La mayoría de los paquetes marshaler no pueden hacer esto incluso después de ordenar una instancia del tipo dado! La mayoría de los marshalers examinan tipos complejos recorriendo el objeto que se está marshaleando y comprobando los tipos solo para los subobjetos visitados. Esto significa que si el objeto complejo contiene un contenedor (puntero, mapa o segmento) que está vacío, el tipo de elemento del contenedor ni siquiera se examina. En contract qs recorre la estructura de tipo del objeto complejo (en lugar del objeto en sí) mientras se crea el marshaler para el tipo para que falle donde tiene que fallar. Considere el siguiente código en el que el paquete estándar "encoding/json" gestiona con éxito un objeto cuyo tipo contiene un tipo no marshalable:

    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
Author: pasztorpisti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-21 22:56:57