Popularity
5.9
Growing
Activity
3.2
-
354
16
11

Programming language: Go
License: MIT License
Tags: Json    

marshmallow alternatives and similar packages

Based on the "JSON" category.
Alternatively, view marshmallow alternatives based on common mentions on social networks and blogs.

Do you think we are missing an alternative of marshmallow or a related project?

Add another 'JSON' Package

README

Marshmallow

Marshmallow Campfire

CodeQL Status Run Tests Dependency Review Go Report Card Manual Code Coverage Go Reference [Licence](LICENSE) Latest Release Top Languages Issues Pull Requests Commits

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() {
    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>
}

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 JSONDataHandler. More info here.

Marshmallow also supports caching of refection information using EnableCache and EnableCustomCache.

Examples can be found [here](example_test.go)

Marshmallow Logo

Marshmallow logo and assets by Adva Rom are licensed under a Creative Commons Attribution 4.0 International License.

Contribute

Any type of contribution is warmly welcome and appreciated ❤️

Marshmallow Logo


*Note that all licence references and agreements mentioned in the marshmallow README section above are relevant to that project's source code only.