Decoding incoming JSON in Golang based on parameter values
I am trying to decode incoming JSON in my REST API written in Go. I am using a function decoder.Decode()
and my problem is that I need to apply certain rules according to which structure should be used in the decoding process, because sometimes JSON contains:
"type": {
"type" : "string",
"maxLength" : 30
},
and sometimes:
"type": {
"type" : "integer",
"max" : 30,
"min" : 10
},
I somehow need to tell Go that "If type.type is a string, use this struct ( type Type_String struct
), and if type.type is an integer, use another struct ( type Type_Integer struct
)". I'm not sure how to do this. One solution I think is to create a generic structure with all possible properties, use it on any object and then filter properties based on the property type
, but this is so messy. I guess I can write my own decoder too, but this is a bit strange too.
I'm new to Go and I'm pretty much accustomed to the free JavaScript sentences.
source to share
You can always decode interface {} as mentioned here: How to access interface fields in json decode?
http://play.golang.org/p/3z8-unhsH4
package main
import (
"encoding/json"
"fmt"
)
var one string = `{"type": {"type": "string", "maxLength":30}}`
var two string = `{"type": {"type": "integer", "max":30, "min":10}}`
func f(data map[string]interface{}) {
t := data["type"]
typemap := t.(map[string]interface{})
t2 := typemap["type"].(string)
switch t2 {
case "string":
fmt.Println("maxlength:", typemap["maxLength"].(float64))
case "integer":
fmt.Println("max:", typemap["max"].(float64))
default:
panic("oh no!")
}
}
func main() {
var jsonR map[string]interface{}
err := json.Unmarshal([]byte(one), &jsonR)
if err != nil {
panic(err)
}
f(jsonR)
json.Unmarshal([]byte(two), &jsonR)
f(jsonR)
}
The idea is to decouple the [string] interface {} map and then cast and compare before accessing the values.
In the above code, the function f is casting and comparing. Given this bad json, I used the wrong t and t2 variable name to represent json values โโof type "at different depths". Once t2 has a value, the switch statement does something with "string" or "integer" and what it does is print the maximum length or maximum value.
source to share
First of all, if the "type" fields depend on the type.type, in my opinion it is better to move it one level up. Something like:
...
"type" : "integer",
"intOptions": {
"max" : 30,
"min" : 10
},
....
Then you can create a structure with just one field:
type Type struct {
Type string
}
and do something like:
myType := new(Type)
json.Unmarshal([]byte(yourJsonString), myType)
And now, depending on the value of myType, you can use different structures to decode your json.
source to share