Categorygithub.com/arloliu/jsonpack
modulepackage
1.0.3
Repository: https://github.com/arloliu/jsonpack.git
Documentation: pkg.go.dev

# README

GoDoc Go Report Card License

Fast and space efficiency JSON serialization golang library. It is a schema oriented design which leverages schema definition to encode JSON document into compact binary encoded format, and decodes back into JSON document.

Introduction

When we want to exchange data between services or over network, the JSON is most popular format to do it. In golang world, the most convenient way is using official encoding/json package to marshal and unmarshal JSON document from/to struct or map. For usual RESTful web service scenario, JSON format is quite convenience and representative, but for real-time message exchanging or other scenarios that has small footprint data and low-latency requirement, JSON is a bit too heavy weight, not only data footprint is not space saving, but also has heavy loading in encode/decode procedure.

So if we want to a compact, small footprint data for exchanging over network, and also leverages the convenience of JSON, we need an encoding format that removes "property name" and other notations likes ':', '[', '{'...etc from original JSON document, and leaves "value" only.

To achieve this goal, we need a schematic to define our JSON document and provide enough information for serialization engine to know sequence and data type of every properties in document. it's the reason why JSONPack is a schema oriented design library.

Key Features

  • Similar Marshal / Unmarshal API to standard encoding/json package.
  • Space saving encoded format, the size of encoded data is similar to Protocol Buffers, can be 30-80% of original JSON document, depends on data.
  • Blazing fast, provides about 3.x decoding speed compared to protobuf and many times than other JSON packages.
  • Memory saving design, avoids any un-necessary memory allocations, suitable for embedded environment.
  • Has production ready javascript implementation Buffer Plus, can be used in node.js and Web browser environment.
  • No need to write schema definition by hand, jsonpack will generate schema definition from golang struct automatically.

How to Get

go get github.com/arloliu/jsonpack

Usage

Example of add schema definition

import "github.com/arloliu/jsonpack"

type Info struct {
	Name string `json:"name"`
	Area uint32 `json:"area"`
	// omit this field
	ExcludeField string `-`
}

jsonPack := jsonpack.NewJSONPack()
sch, err := jsonPack.AddSchema("Info", Info{}, jsonpack.LittleEndian)

Example of encoding data with Info struct

infoStruct := &Info{
    Name: "example name",
    Area: 888,
}
// encodedResult1 contains encoded data,
encodedResult1, err := jsonPack.Marshal("Info", infoStruct)

Example of encoding data with golang map

infoMap := map[string]interface{} {
	"name": "example name",
	"area": 888,
}

encodedResult2, err := jsonPack.Marshal("Info", infoMap)

Example of decoding data

decodeInfoStruct = Info{}
err := jsonPack.Decode("Info", encodedResult1, &decodeInfoStruct)

decodeInfoMap = make(map[string]interface{})
err := jsonPack.Decode("Info", encodedResult2, &decodeInfoMap)

Benchmark

The benchmark result is a important reference but not always suitable for every scenarios.

Test environment: Intel i7-9700K [email protected].

Benchmark code is here

Sorts from fastest to slowest in the following.

Encode from golang map

ns/opallocation bytesallocation times
jsonpack1933 ns/op752 B/op2 allocs/op
jsoniter10134 ns/op3320 B/op46 allocs/op
std. json23560 ns/op8610 B/op171 allocs/op
goccy75298 ns/op82639 B/op651 allocs/op

Decode into golang map

ns/opallocation bytesallocation times
jsonpack6461 ns/op6512 B/op96 allocs/op
jsoniter17436 ns/op9666 B/op290 allocs/op
std. json18949 ns/op8864 B/op228 allocs/op
goccy19985 ns/op15900 B/op316 allocs/op

Encode from golang struct

ns/opallocation bytesallocation times
jsonpack1834 ns/op800 B/op3 allocs/op
protobuf1972 ns/op896 B/op1 allocs/op
goccy2166 ns/op1280 B/op1 allocs/op
jsoniter3372 ns/op1296 B/op3 allocs/op
std. json3578 ns/op1280 B/op1 allocs/op

Decode into golang struct

ns/opallocation bytesallocation times
jsonpack1475 ns/op96 B/op2 allocs/op
goccy3284 ns/op2215 B/op5 allocs/op
jsoniter4680 ns/op1072 B/op79 allocs/op
protobuf5075 ns/op3152 B/op84 allocs/op
std. json18378 ns/op1232 B/op69 allocs/op

The benchmark result indicates jsonpack keeps constant performance on both encoding and encoding side, and keeps very low memory allocation size and times.

Explanation of Benchmark Result

The benchmark result also delivers some important messages.

  1. The performance of operating with golang map sucks.
  2. The pointer of type likes *string, *int32 cost twice of time.
  3. Golang reflection is expensive, reflect.ValueOf(...) is very expensive.

Performance Tips

According to the explanation of benchmarking and some tests during the implementation stage of this library, there are some suggestions in the following.

  1. It's better to use struct instead of map for encode/decode if possible.
  2. When declares struct fields, declares it as value instead of pointer to value gives performance gain.
  3. Designs a small and compacted structure, uses number type to represent enum. fields instead of declares it as string type.

# Packages

Package buffer provides a easy way to manipulate byte slices.
No description provided by the author

# Functions

NewJSONPack returns a new jsonpack instance.

# Constants

big endian byte order.
little endian byte order.

# Structs

CompileError represents an error from calling AddSchema method, it indicates there has an error occurs in compiling procedure of schema definition.
DecodeError represents an error from calling Decode or Unmarshal methods.
EncodeError represents an error from calling Encode or Marshal methods.
JSONPack provides top-level operations for schema.
NotImplementedError is returned when the operation in handler doesn't implemented.
Schema represents a compiled jsonpack schema instance which created by jsonpack.AddSchema function.
SchemaDef represents a schema definition that defines the structure of JSON document.
SchemaNonExistError indicates an error that occurs when pre-compiled schema definition does not exist.
StructFieldNonExistError indicates an error that occurs when structure doesn't have required field.
TypeAssertionError indicates an error that occurs when doing data type asserrion.
UnknownTypeError is returned when un-supported data type found, it happens in AddSchema method.
WrongTypeError is returned when wrong data type found in data, it happens in Encode/Decode methods.

# Type aliases

ByteOrder represents the byte order of numeric type that will be encoded to and decoded from.