Polygo is a lightweight Go package for decoding polymorphic JSON responses effortlessly.
Dealing with APIs that return various types of objects can be challenging.
Polygo simplifies this process by allowing you to map your types into a common interface.
Consider an API endpoint /v1/shapes
that returns a list of shapes, each defined by a type field:
[
{ "type": "circle", "radius": 5 },
{ "type": "square", "side": 3 }
]
With Polygo, you can easily handle this polymorphic JSON response. Here's how.
- Create a Decoder: Initialize a decoder with a common interface and the field name used to check the object type.
- Register Types: Register your concrete types with the decoder.
- Unmarshal JSON: Use one of the available functions to unmarshal your JSON data.
// Define your shape interface
type Shape interface {
Area() float64
}
// Create a decoder specifying the interface and the field name,
// and register your concrete types
decoder := polygo.NewDecoder[Shape]("type").
Register("circle", Circle{}).
Register("square", Square{})
// unmarshal your JSON
shapes, _ := decoder.UnmarshalArray(jsonBytes)
for _, shape := range shapes {
// use the methods defined by the interface
fmt.Printf("shape area: %v\n", shape.Area())
// or check the concrete type if needed
switch s := shape.(type) {
case *Circle:
fmt.Printf("circle radius: %v\n", s.Radius)
case *Square:
fmt.Printf("square side: %v\n", s.Side)
}
}
UnmarshalObject
will unmarshal a plain object:
jsonBody := []byte(`{ "type": "circle", "radius": 5 }`)
shape, err := decoder.UnmarshalObject(jsonBody)
if err != nil {
return err
}
UnmarshalArray
will unmarshal an array of objects:
jsonBody := []byte(`[
{ "type": "circle", "radius": 5 },
{ "type": "square", "side": 3 }
]`)
shapes, err := decoder.UnmarshalArray(jsonBody)
if err != nil {
return err
}
UnmarshalInnerObject
will unmarshal an object, looking into the specified path (using the github.com/tidwall/gjson library).
jsonBody := []byte(`{
"data": { "type": "circle", "radius": 5 }
}`)
shapes, err := decoder.UnmarshalInnerObject("data", jsonBody)
if err != nil {
return err
}
UnmarshalInnerArray
will unmarshal an array of objects, looking into the specified path (using the github.com/tidwall/gjson library).
jsonBody := []byte(`{
"data": [
{ "type": "circle", "radius": 5 },
{ "type": "square", "side": 3 }
]
}`)
shapes, err := decoder.UnmarshalInnerArray("data", jsonBody)
if err != nil {
return err
}
If your data is wrapped in an object with fields that you are interested to check, you should use a struct with a json.RawMessage
field. Then you can unmarshal this field with the decoder.
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data json.RawMessage `json:"data"`
}
jsonData := []byte(`{
"code": 200,
"message": "all good",
"data": [
{ "type": "circle", "radius": 5 },
{ "type": "square", "side": 3 }
]
}`)
var resp Response
err := json.Unmarshal(jsonData, &resp)
if err != nil {
return err
}
shapes, err := decoder.UnmarshalArray(resp.Data)
if err != nil {
return err
}
To use Polygo in your Go project, simply import it:
import "github.com/enrichman/polygo"
Contributions are welcome! Feel free to open issues or pull requests on GitHub.
If you like the project please star it on Github 🌟, and feel free to drop me a note on Twitterhttps://twitter.com/enrichmann, or open an issue!