Marshmallow
Marshmallow provides a flexible and performant JSON unmarshalling in Go. It specializes in dealing with unstructured struct - when some fields are known and some aren't, with zero performance overhead nor extra coding needed.
Install / Use
/learn @HumanSecurity/MarshmallowREADME
Marshmallow

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.
Contents
Install
go get -u github.com/perimeterx/marshmallow
Usage
package main
import (
"fmt"
"github.com/perimeterx/marshmallow"
)
func main() {
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>
}
Examples can be found here
Performance Benchmark And Alternatives
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|
When Should I Use Marshmallow
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
}
API
Marshmallow exposes two main API functions - Unmarshal and UnmarshalFromJSONMap. While unmarshalling, marshmallow supports the following optional options:
- Setting the mode for handling invalid data using the WithMode function.
- Excluding known fields from the result map using the WithExcludeKnownFieldsFromMap function.
- Skipping struct population to boost performance using the WithSkipPopulateStruct function.
In order to capture unknown nested fields, structs must implement JSONDataErrorHandler. More info here.
Marshmallow also supports caching of refection information using EnableCache and EnableCustomCache.
Contact and Contribute
Reporting issues and requesting features may be done in our GitHub issues page. Discussions may be conducted in our GitHub discussions page. For any further questions or comments you can reach us out at open-source@humansecurity.com.
Any type of contribution is warmly welcome and appreciated ❤️ Please read our contribution guide for more info.
If you're looking for something to get started with, tou can always follow our issues page and look for good first issue and help wanted labels.
Marshmallow Logo
Marshmallow logo and assets by [Adva Rom](https://www.linked
Related Skills
xurl
334.9kA CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.
kubeshark
11.8kCluster-wide network observability for Kubernetes. Captures L4 packets, L7 API calls, and decrypted TLS traffic using eBPF, with full Kubernetes context. Available to AI agents via MCP and human operators via dashboard.
wanwu
4.2kChina Unicom's Yuanjing Wanwu Agent Platform is an enterprise-grade, multi-tenant AI agent development platform. It helps users build applications such as intelligent agents, workflows, and rag, and also supports model management. The platform features a developer-friendly license, and we welcome all developers to build upon the platform.
gin-vue-admin
24.5k🚀Vite+Vue3+Gin拥有AI辅助的基础开发平台,企业级业务AI+开发解决方案,内置mcp辅助服务,内置skills管理,支持TS和JS混用。它集成了JWT鉴权、权限管理、动态路由、显隐可控组件、分页封装、多点登录拦截、资源权限、上传下载、代码生成器、表单生成器和可配置的导入导出等开发必备功能。
