32

I would like to marshal in and out of x-www-form-urlencoding similar to how you can do it with json or xml. Is there an existing package to do this, or are there any documents on how to implement one myself if none exist?

placeybordeaux
  • 2,138
  • 1
  • 20
  • 42
  • 2
    net/url in stdlib does what you want, I believe. Keep in mind there's a solid http client and server standard that have to do these things. – Dustin Mar 22 '14 at 18:18
  • 4
    ParseQuery returns a map[string][]string, which is very useful, but it does not marshal directly to a struct as 'encoding/json' does. – placeybordeaux Mar 22 '14 at 18:46
  • I have no idea where you got that information. It is incorrect according to the documentation and my experience using it. – Dustin Mar 23 '14 at 16:29
  • 1
    If you want to argue about it, it would be pretty good to link to the documentation you are getting your information from. For me I was looking at `net/url.ParseQuery` which returns `net/url.Values` which is defined as `type Values map[string][]string`. see more here: http://golang.org/pkg/net/url/#ParseQuery – placeybordeaux Mar 23 '14 at 16:41
  • That makes it a url.Values type, not a map[string][]string -- you can convert between them, but they are not interchangeable. The former has a method that does what you want. – Dustin Mar 29 '14 at 01:15
  • I do not see where Values implements an Encoding or Decoding interface, which is what I was asking for. Not a way to parse the string, a way to marshal it. – placeybordeaux Mar 29 '14 at 14:38
  • The link above describes an `.Encode()` method, which does what I believe you're describing. – Dustin Mar 30 '14 at 07:00
  • It does not have Decode, which is a lot harder. You can marshal in, but not out. – placeybordeaux Mar 30 '14 at 15:30
  • What is the difference between Decode and the exact function you linked to? – Dustin Mar 31 '14 at 06:54
  • One of them marshals directly into arbitrary structs and the other simply outputs a map[string][]string object. If you really don't understand I would recommend asking a question as opposed to having this conversation in a comments section of a dead question. – placeybordeaux Mar 31 '14 at 16:15

4 Answers4

23

gorilla/schema is popular and well maintained:

e.g.

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 is also an alternative.

Update May 23rd 2015:

  • gorilla/schema is still my pick as one of the most-supported map-to-struct packages, with POST form values being a common use-case.
  • goji/param is also fairly solid and has many of the same features.
  • mholt/binding is a little more feature packed at the (IMO) expense of a slightly more complex API.

I've been using gorilla/schema for a couple of years now and haven't had any major issues with it. I use it in conjunction with vala for validating inputs (not nil, too short, too long, etc) before they hit the DB.

user387049
  • 6,647
  • 8
  • 53
  • 55
elithrar
  • 23,364
  • 10
  • 85
  • 104
  • Awesome I didn't see goforms, I like that there are are min max and required fields. I might just extend goforms to include an actual default value. – placeybordeaux Mar 23 '14 at 16:44
  • Just want to note that gorilla schema doesn't seems to be well supported. I.e. slices of structs can't be marshalled even though the readme says it can. There is an open ticket for it. – pwaterz Apr 13 '21 at 14:22
8

I just found https://github.com/ajg/form which is exactly what I was looking for. There is also https://github.com/gorilla/schema for strictly decoding and https://github.com/google/go-querystring for strictly encoding.

placeybordeaux
  • 2,138
  • 1
  • 20
  • 42
6

net/url seems to handle this just fine:

package main

import (
   "fmt"
   "net/url"
)

func main() {
   {
      m := url.Values{
         "CR": {"\r"}, "LF": {"\n"},
      }
      s := m.Encode()
      fmt.Println(s) // CR=%0D&LF=%0A
   }
   {
      s := "CR=%0D&LF=%0A"
      m, e := url.ParseQuery(s)
      if e != nil {
         panic(e)
      }
      fmt.Printf("%q\n", m) // map["CR":["\r"] "LF":["\n"]]
   }
}
Zombo
  • 1
  • 62
  • 391
  • 407
  • 1
    I think this should be the right answer, as all the other answers do much more than just marshalling and unmarshalling the data (they all parse the content into a predefined struct, which is useful, but not the question asked). If you want to just marshal/unmarshal all the data within the url parameters, this should be the answer. – Hanno Kolvenbach Sep 18 '21 at 14:47
  • Agreed, especially true now that the Gorilla project mentioned in the accepted answer is well-and-truly dead. – Benjamin Nolan Feb 23 '23 at 11:27
2

https://github.com/google/go-querystring is good, but doesn't support maps (and slices of maps).

I started https://github.com/drewlesueur/querystring for map support. (It doesn't support structs yet, but pull requests welcome).

Drew LeSueur
  • 19,185
  • 29
  • 89
  • 106
  • It looks like go-querystring only allows for encoding, not decoding. Your project looks like it could work, but it is not idiomatic, why not name those functions Marshal and Unmarshal and meet the same interface? – placeybordeaux May 29 '15 at 12:51
  • Thank for the feedback. I could make mine more idiomatic. Mine currently only encodes though too. – Drew LeSueur May 29 '15 at 14:03