Package sonh/qs encodes structs into url.Values.
go get github.com/sonh/qs
import (
"github.com/sonh/qs"
)
Package qs exports NewEncoder()
function to create an encoder.
Encoder caches struct info to speed up encoding process, use a single instance is highly recommended.
Use WithTagAlias()
func to register custom tag alias (default is qs
)
encoder = qs.NewEncoder(
qs.WithTagAlias("myTag"),
)
Encoder has Values()
and Encode()
functions to encode structs into url.Values
.
- all basic types (
bool
,uint
,string
,float64
,...) struct
slice
,array
pointer
time.Time
- custom type
type Query struct {
Tags []string `qs:"tags"`
Limit int `qs:"limit"`
From time.Time `qs:"from"`
Active bool `qs:"active,omitempty"` //omit empty value
Ignore float64 `qs:"-"` //ignore
}
query := &Query{
Tags: []string{"docker", "golang", "reactjs"},
Limit: 24,
From: time.Unix(1580601600, 0).UTC(),
Ignore: 0,
}
encoder := qs.NewEncoder()
values, err := encoder.Values(query)
if err != nil {
// Handle error
}
fmt.Println(values.Encode()) //(unescaped) output: "from=2020-02-02T00:00:00Z&limit=24&tags=docker&tags=golang&tags=reactjs"
Use int
option to encode bool to integer
type Query struct {
DefaultFmt bool `qs:"default_fmt"`
IntFmt bool `qs:"int_fmt,int"`
}
query := &Query{
DefaultFmt: true,
IntFmt: true,
}
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) // (unescaped) output: "default_fmt=true&int_fmt=1"
By default, package encodes time.Time values as RFC3339 format.
Including the "second"
or "millis"
option to signal that the field should be encoded as second or millisecond.
type Query struct {
Default time.Time `qs:"default_fmt"`
Second time.Time `qs:"second_fmt,second"` //use `second` option
Millis time.Time `qs:"millis_fmt,millis"` //use `millis` option
}
t := time.Unix(1580601600, 0).UTC()
query := &Query{
Default: t,
Second: t,
Millis: t,
}
encoder := qs.NewEncoder()
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) // (unescaped) output: "default_fmt=2020-02-02T00:00:00Z&millis_fmt=1580601600000&second_fmt=1580601600"
Slice and Array default to encoding into multiple URL values of the same value name.
type Query struct {
Tags []string `qs:"tags"`
}
values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) //(unescaped) output: "tags=foo&tags=bar"
Including the comma
option to signal that the field should be encoded as a single comma-delimited value.
type Query struct {
Tags []string `qs:"tags,comma"`
}
values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) //(unescaped) output: "tags=foo,bar"
Including the bracket
option to signal that the multiple URL values should have "[]" appended to the value name.
type Query struct {
Tags []string `qs:"tags,bracket"`
}
values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) //(unescaped) output: "tags[]=foo&tags[]=bar"
The index
option will append an index number with brackets to value name.
type Query struct {
Tags []string `qs:"tags,index"`
}
values, _ := encoder.Values(&Query{Tags: []string{"foo","bar"}})
fmt.Println(values.Encode()) //(unescaped) output: "tags[0]=foo&tags[1]=bar"
All nested structs are encoded including the parent value name with brackets for scoping.
type User struct {
Verified bool `qs:"verified"`
From time.Time `qs:"from,millis"`
}
type Query struct {
User User `qs:"user"`
}
query := Query{
User: User{
Verified: true,
From: time.Now(),
},
}
values, _ := encoder.Values(query)
fmt.Println(values.Encode()) //(unescaped) output: "user[from]=1601623397728&user[verified]=true"
Implement funcs:
EncodeParam
to encode itself into query param.IsZero
to check whether an object is zero to determine whether it should be omitted when encoding.
type NullableName struct {
First string
Last string
}
func (n NullableName) EncodeParam() (string, error) {
return n.First + n.Last, nil
}
func (n NullableName) IsZero() bool {
return n.First == "" && n.Last == ""
}
type Struct struct {
User NullableName `qs:"user"`
Admin NullableName `qs:"admin,omitempty"`
}
s := Struct{
User: NullableName{
First: "son",
Last: "huynh",
},
}
encoder := qs.NewEncoder()
values, err := encoder.Values(&s)
if err != nil {
// Handle error
fmt.Println("failed")
return
}
fmt.Println(values.Encode()) //(unescaped) output: "user=sonhuynh"
- if elements in
slice/array
arestruct
data type, multi-level nesting are limited - no decoder yet
Will improve in future versions
Distributed under MIT License, please see license file in code for more details.