
Security News
How Enterprise Security Is Adapting to AI-Accelerated Threats
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.
github.com/PerimeterX/marshmallow
Advanced tools

Marshmallow package provides a simple API to perform flexible and performant JSON unmarshalling in Go.
Marshmallow specializes in dealing with unstructured struct - when some fields are known and some aren't, with zero performance overhead nor extra coding needed. While unmarshalling, marshmallow allows fully retaining the original data and access it via a typed struct and a dynamic map.
go get -u github.com/perimeterx/marshmallow
package main
import (
"fmt"
"github.com/perimeterx/marshmallow"
)
func main() {
marshmallow.EnableCache() // this is used to boost performance, read more below
v := struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}{}
result, err := marshmallow.Unmarshal([]byte(`{"foo":"bar","boo":[1,2,3],"goo":12.6}`), &v)
fmt.Printf("v=%+v, result=%+v, err=%v", v, result, err)
// Output: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar goo:12.6], err=<nil>
}
Marshmallow performs best when dealing with mixed data - when some fields are known and some are unknown. More info below. Other solutions are available for this kind of use case, each solution is explained and documented in the link below. The full benchmark test can be found here.
| Benchmark | Iterations | Time/Iteration | Bytes Allocated | Allocations |
|---|---|---|---|---|
| unmarshall twice | 228693 | 5164 ns/op | 1640 B/op | 51 allocs/op |
| raw map | 232236 | 5116 ns/op | 2296 B/op | 53 allocs/op |
| go codec | 388442 | 3077 ns/op | 2512 B/op | 37 allocs/op |
| marshmallow | 626168 | 1853 ns/op | 608 B/op | 18 allocs/op |
| marshmallow without populating struct | 678616 | 1751 ns/op | 608 B/op | 18 allocs/op |
Marshmallow provides the best performance (up to X3 faster) while not requiring any extra coding.
In fact, marshmallow performs as fast as normal json.Unmarshal call, however, such a call causes loss of data for all
the fields that did not match the given struct. With marshmallow you never lose any data.
| Benchmark | Iterations | Time/Iteration | Bytes Allocated | Allocations |
|---|---|---|---|---|
| marshmallow | 626168 | 1853 ns/op | 608 B/op | 18 allocs/op |
| native library | 652106 | 1845 ns/op | 304 B/op | 11 allocs/op |
| marshmallow without populating struct | 678616 | 1751 ns/op | 608 B/op | 18 allocs/op |
Marshmallow is best suited for use cases where you are interested in all the input data, but you have predetermined information only about a subset of it. For instance, if you plan to reference two specific fields from the data, then iterate all the data and apply some generic logic. How does it look with the native library:
func isAllowedToDrive(data []byte) (bool, error) {
result := make(map[string]interface{})
err := json.Unmarshal(data, &result)
if err != nil {
return false, err
}
age, ok := result["age"]
if !ok {
return false, nil
}
a, ok := age.(float64)
if !ok {
return false, nil
}
if a < 17 {
return false, nil
}
hasDriversLicense, ok := result["has_drivers_license"]
if !ok {
return false, nil
}
h, ok := hasDriversLicense.(bool)
if !ok {
return false, nil
}
if !h {
return false, nil
}
for key := range result {
if strings.Contains(key, "prior_conviction") {
return false, nil
}
}
return true, nil
}
And with marshmallow:
func isAllowedToDrive(data []byte) (bool, error) {
v := struct {
Age int `json:"age"`
HasDriversLicense bool `json:"has_drivers_license"`
}{}
result, err := marshmallow.Unmarshal(data, &v)
if err != nil {
return false, err
}
if v.Age < 17 || !v.HasDriversLicense {
return false, nil
}
for key := range result {
if strings.Contains(key, "prior_conviction") {
return false, nil
}
}
return true, nil
}
Marshmallow exposes two main API functions - Unmarshal and UnmarshalFromJSONMap. While unmarshalling, marshmallow supports the following optional options:
In order to capture unknown nested fields, structs must implement JSONDataHandler. More info here.
Marshmallow also supports caching of refection information using EnableCache and EnableCustomCache.
Examples can be found here
Marshmallow logo and assets by Adva Rom are licensed under a Creative Commons Attribution 4.0 International License.
Any type of contribution is warmly welcome and appreciated ❤️

FAQs
Unknown package
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.