• Stars
    star
    347
  • Rank 117,742 (Top 3 %)
  • Language
    Go
  • License
    MIT License
  • Created about 2 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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.

Marshmallow

Marshmallow Campfire

CodeQL Status Run Tests Dependency Review Go Report Card Manual Code Coverage Go Reference Licence Latest Release Top Languages Issues Pull Requests Commits Contributor Covenant

marshmallow-gopher

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 performance comparison

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:

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 [email protected].

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 are licensed under a Creative Commons Attribution 4.0 International License.

Marshmallow Logo

More Repositories

1

restringer

A Javascript Deobfuscator
JavaScript
263
star
2

go-project-structure

146
star
3

perimeterx-nginx-plugin

PerimeterX NGINX Lua Middleware
Lua
42
star
4

obfuscation-detector

Detect different types of JS obfuscation by their AST structure
JavaScript
36
star
5

CVE-2020-6519

JavaScript
26
star
6

perimeterx-node-express

PerimeterX Express.js middleware to monitor and block traffic according to PerimeterX risk score
JavaScript
25
star
7

ok-lets-go

Three Approaches to Structuring Go Code
Go
24
star
8

bot-tools

HTML
22
star
9

map-events

events mapped out completely cross browsers
JavaScript
20
star
10

flast

Provides a flat Abstract Syntax Tree and an Arborist to trim and modify the tree
JavaScript
19
star
11

perimeterx-php-sdk

PerimeterX PHP SDK
PHP
16
star
12

perimeterx-java-sdk

PerimeterX JAVA SDK
Java
15
star
13

perimeterx-python-wsgi

PerimeterX WSGI Middleware
Python
14
star
14

gitapp_alert_on_public

A service for finding and alerting on newly created public repositories for GitHub users who are part of a GitHub organization.
Python
14
star
15

px-iOS-Framework

HUMAN iOS framework
Objective-C
14
star
16

CVE-2019-18426

10
star
17

node-http2-server-push

HTML
8
star
18

perimeterx-kong-plugin

PerimeterX Kong plugin
Lua
6
star
19

web-security-analysis-toolkit-workshop

Sample code and examples for the Web Security Analysis Toolkit workshop.
6
star
20

rpc-protocol-benchmark

Go
5
star
21

perimeterx-node-core

JavaScript
5
star
22

perimeterx-asp-net

C#
4
star
23

perimeterx-abr-samples

Samples for the Advanced Blocking Response feature
HTML
4
star
24

map-events-website

a website for https://github.com/perimeterx/event-handlers project
JavaScript
3
star
25

perimeterx-public-devtools

JavaScript
3
star
26

Data-Defender

A tool to help organizations improve efficiency and saving cost of BigQuery data
Python
2
star
27

px-mobile-sdk-demo-app

PerimeterX Mobile SDK - Demo App
C++
2
star
28

perimeterx-ruby-sdk

perimeterx ruby sdk
Ruby
2
star
29

envite

A framework to manage development and testing environments
Go
2
star
30

perimeterx-python-3-wsgi

PerimeterX WSGI Middleware for Python 3
Python
1
star
31

eslint-config-perimeterx

JavaScript
1
star
32

ip-clipboard

macOS Automator workflow to copy your external ip address to clipboard
1
star