Name: sheriff
Owner: Liip
Description: Conditional marshalling for Go
Created: 2017-01-23 10:03:16.0
Updated: 2018-03-27 10:53:42.0
Pushed: 2018-03-01 13:33:35.0
Homepage: https://godoc.org/github.com/liip/sheriff
Size: 51
Language: Go
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
et github.com/liip/sheriff
Package sheriff marshals structs conditionally based on tags on the fields.
A typical use is an API which marshals structs into JSON and maintains different API versions. Using sheriff, struct fields can be annotated with API version and group tags.
By invoking sheriff with specific options, those tags determine whether a field will be added to the output map or not. It can then be marshalled using “encoding/json”.
Groups can be used for limiting the output based on freely defined parameters. For example: restrict marshalling the email
address of a user to the user itself by just adding the group personal
if the user fetches his profile.
Multiple groups can be separated by comma.
Example:
GroupsExample struct {
Username string `json:"username" groups:"api"`
Email string `json:"email" groups:"personal"`
SomethingElse string `json:"something_else" groups:"api,personal"`
Since specifies the version since that field is available. It's inclusive and SemVer compatible using
github.com/hashicorp/go-version.
If you specify version 2
in a tag, this version will be output in case you specify version >=2.0.0
as the API version.
Example:
SinceExample struct {
Username string `json:"username" since:"2.1.0"`
Email string `json:"email" since:"2"`
Until specifies the version until that field is available. It's the opposite of since, inclusive and SemVer
compatible using github.com/hashicorp/go-version.
If you specify version 2
in a tag, this version will be output in case you specify version <=2.0.0
as the API version.
Example:
UntilExample struct {
Username string `json:"username" until:"2.1.0"`
Email string `json:"email" until:"2"`
age main
rt (
"encoding/json"
"fmt"
"log"
"github.com/hashicorp/go-version"
"github.com/liip/sheriff"
User struct {
Username string `json:"username" groups:"api"`
Email string `json:"email" groups:"personal"`
Name string `json:"name" groups:"api"`
Roles []string `json:"roles" groups:"api" since:"2"`
UserList []User
MarshalUsers(version *version.Version, groups []string, users UserList) ([]byte, error) {
o := &sheriff.Options{
Groups: groups,
ApiVersion: version,
}
data, err := sheriff.Marshal(o, users)
if err != nil {
return nil, err
}
return json.MarshalIndent(data, "", " ")
main() {
users := UserList{
User{
Username: "alice",
Email: "alice@example.org",
Name: "Alice",
Roles: []string{"user", "admin"},
},
User{
Username: "bob",
Email: "bob@example.org",
Name: "Bob",
Roles: []string{"user"},
},
}
v1, err := version.NewVersion("1.0.0")
if err != nil {
log.Panic(err)
}
v2, err := version.NewVersion("2.0.0")
output, err := MarshalUsers(v1, []string{"api"}, users)
if err != nil {
log.Panic(err)
}
fmt.Println("Version 1 output:")
fmt.Printf("%s\n\n", output)
output, err = MarshalUsers(v2, []string{"api"}, users)
if err != nil {
log.Panic(err)
}
fmt.Println("Version 2 output:")
fmt.Printf("%s\n\n", output)
output, err = MarshalUsers(v2, []string{"api", "personal"}, users)
if err != nil {
log.Panic(err)
}
fmt.Println("Version 2 output with personal group too:")
fmt.Printf("%s\n\n", output)
utput:
ersion 1 output:
{
"name": "Alice",
"username": "alice"
},
{
"name": "Bob",
"username": "bob"
}
ersion 2 output:
{
"name": "Alice",
"roles": [
"user",
"admin"
],
"username": "alice"
},
{
"name": "Bob",
"roles": [
"user"
],
"username": "bob"
}
ersion 2 output with personal group too:
{
"email": "alice@example.org",
"name": "Alice",
"roles": [
"user",
"admin"
],
"username": "alice"
},
{
"email": "bob@example.org",
"name": "Bob",
"roles": [
"user"
],
"username": "bob"
}
There's a simple benchmark in bench_test.go
which compares running sheriff -> JSON versus just marshalling into JSON
and runs on every build. Just marshalling JSON itself takes usually between 3 and 5 times less nanoseconds per operation
compared to running sheriff and JSON.
Want to make sheriff faster? Please send us your pull request or open an issue discussing a possible improvement ?!
mweibel/php-to-go is a code generator translating PHP models (using JMS serializer) to Go structs with sheriff tags. The two projects were initially developed together and just recently php-to-go has been split out and published too.