gonestedx-www-form-urlencoded

Get nested key value pair of x-www-form-urlencoded request in JSON format in golang


I have use case where we are getting nested key value in x-www-form-urlencoded body like below

name=abc&age=12&notes[key1]=value1&notes[key2]=value2

I tried url.ParseQuery("name=abc&age=12&notes\[key1\]=value1&notes\[key2\]=value2") but it's giving

{
  "name": "abc",
  "age": 12,
  "notes[key1]": "value1",
  "notes[key2]": "value2"
}

How can I get this value in below JSON format for above body

{
  "name": "abc",
  "age": 12,
  "notes": {
    "key1": "value1",
    "key2": "value2"
  }
}

There is possibility that notes might be in 3 level nested format

I have tried url.ParseQuery and r.Form but both of them giving notes[key1] and notes[key2].


Solution

  • To unmarshal nested key values with this type of query string parameter names, it's possible to use derekstavis/go-qs which is a port of Rack's query string parser.

    This returns a map[string]interface{} with nested key values as follows.

    Of note, the value for age is returned as a string, however, this is the same for url.ParseQuery. If marshaling this to an integer is desired, the package can be forked and modified.

    {
      "age": "12",
      "name": "abc",
      "notes": {
        "key1": "value1",
        "key2": "value2"
      }
    }
    

    A complete example is available on the Go Playground with the following code:

    Go Playground URL: https://go.dev/play/p/Px7uZWRNs5V

    package main
    
    import (
        "encoding/json"
        "fmt"
        "log"
    
        qs "github.com/derekstavis/go-qs"
    )
    
    func main() {
        v := "name=abc&age=12&notes[key1]=value1&notes[key2]=value2"
    
        q, err := qs.Unmarshal(v)
        if err != nil {
            log.Fatal(err)
        }
    
        j, err := json.MarshalIndent(q, "", "  ")
        if err != nil {
            log.Fatal(err)
        }
    
        fmt.Println(string(j))
    }