:steam_locomotive: Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

Package form

Project status Build Status Coverage Status Go Report Card GoDoc License Gitter

Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values.

It has the following features:

  • Supports map of almost all types.
  • Supports both Numbered and Normal arrays eg. "Array[0]" and just "Array" with multiple values passed.
  • Slice honours the specified index. eg. if "Slice[2]" is the only Slice value passed down, it will be put at index 2; if slice isn't big enough it will be expanded.
  • Array honours the specified index. eg. if "Array[2]" is the only Array value passed down, it will be put at index 2; if array isn't big enough a warning will be printed and value ignored.
  • Only creates objects as necessary eg. if no array or map values are passed down, the array and map are left as their default values in the struct.
  • Allows for Custom Type registration.
  • Handles time.Time using RFC3339 time format by default, but can easily be changed by registering a Custom Type, see below.
  • Handles Encoding & Decoding of almost all Go types eg. can Decode into struct, array, map, int... and Encode a struct, array, map, int...

Common Questions

  • Does it support encoding.TextUnmarshaler? No because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.
  • Mixing array/slice with array[idx]/slice[idx], in which order are they parsed? array/slice then array[idx]/slice[idx]

Supported Types ( out of the box )

  • string
  • bool
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • struct and anonymous struct
  • interface{}
  • time.Time - by default using RFC3339
  • a pointer to one of the above types
  • slice, array
  • map
  • custom types can override any of the above types
  • many other types may be supported inherently

NOTE: map, struct and slice nesting are ad infinitum.

Installation

Use go get.

go get github.com/go-playground/form

Then import the form package into your own code.

import "github.com/go-playground/form/v4"

Usage

  • Use symbol . for separating fields/structs. (eg. structfield.field)
  • Use [index or key] for access to index of a slice/array or key for map. (eg. arrayfield[0], mapfield[keyvalue])
<form method="POST">
  <input type="text" name="Name" value="joeybloggs"/>
  <input type="text" name="Age" value="3"/>
  <input type="text" name="Gender" value="Male"/>
  <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
  <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
  <input type="text" name="Address[1].Name" value="26 There Blvd."/>
  <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
  <input type="text" name="active" value="true"/>
  <input type="text" name="MapExample[key]" value="value"/>
  <input type="text" name="NestedMap[key][key]" value="value"/>
  <input type="text" name="NestedArray[0][0]" value="value"/>
  <input type="submit"/>
</form>

Examples

Decoding

package main

import (
	"fmt"
	"log"
	"net/url"

	"github.com/go-playground/form/v4"
)

// Address contains address information
type Address struct {
	Name  string
	Phone string
}

// User contains user information
type User struct {
	Name        string
	Age         uint8
	Gender      string
	Address     []Address
	Active      bool `form:"active"`
	MapExample  map[string]string
	NestedMap   map[string]map[string]string
	NestedArray [][]string
}

// use a single instance of Decoder, it caches struct info
var decoder *form.Decoder

func main() {
	decoder = form.NewDecoder()

	// this simulates the results of http.Request's ParseForm() function
	values := parseForm()

	var user User

	// must pass a pointer
	err := decoder.Decode(&user, values)
	if err != nil {
		log.Panic(err)
	}

	fmt.Printf("%#v\n", user)
}

// this simulates the results of http.Request's ParseForm() function
func parseForm() url.Values {
	return url.Values{
		"Name":                []string{"joeybloggs"},
		"Age":                 []string{"3"},
		"Gender":              []string{"Male"},
		"Address[0].Name":     []string{"26 Here Blvd."},
		"Address[0].Phone":    []string{"9(999)999-9999"},
		"Address[1].Name":     []string{"26 There Blvd."},
		"Address[1].Phone":    []string{"1(111)111-1111"},
		"active":              []string{"true"},
		"MapExample[key]":     []string{"value"},
		"NestedMap[key][key]": []string{"value"},
		"NestedArray[0][0]":   []string{"value"},
	}
}

Encoding

package main

import (
	"fmt"
	"log"

	"github.com/go-playground/form/v4"
)

// Address contains address information
type Address struct {
	Name  string
	Phone string
}

// User contains user information
type User struct {
	Name        string
	Age         uint8
	Gender      string
	Address     []Address
	Active      bool `form:"active"`
	MapExample  map[string]string
	NestedMap   map[string]map[string]string
	NestedArray [][]string
}

// use a single instance of Encoder, it caches struct info
var encoder *form.Encoder

func main() {
	encoder = form.NewEncoder()

	user := User{
		Name:   "joeybloggs",
		Age:    3,
		Gender: "Male",
		Address: []Address{
			{Name: "26 Here Blvd.", Phone: "9(999)999-9999"},
			{Name: "26 There Blvd.", Phone: "1(111)111-1111"},
		},
		Active:      true,
		MapExample:  map[string]string{"key": "value"},
		NestedMap:   map[string]map[string]string{"key": {"key": "value"}},
		NestedArray: [][]string{{"value"}},
	}

	// must pass a pointer
	values, err := encoder.Encode(&user)
	if err != nil {
		log.Panic(err)
	}

	fmt.Printf("%#v\n", values)
}

Registering Custom Types

Decoder

decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
	return time.Parse("2006-01-02", vals[0])
}, time.Time{})

ADDITIONAL: if a struct type is registered, the function will only be called if a url.Value exists for the struct and not just the struct fields eg. url.Values{"User":"Name%3Djoeybloggs"} will call the custom type function with 'User' as the type, however url.Values{"User.Name":"joeybloggs"} will not.

Encoder

encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
	return []string{x.(time.Time).Format("2006-01-02")}, nil
}, time.Time{})

Ignoring Fields

you can tell form to ignore fields using - in the tag

type MyStruct struct {
	Field string `form:"-"`
}

Omitempty

you can tell form to omit empty fields using ,omitempty or FieldName,omitempty in the tag

type MyStruct struct {
	Field  string `form:",omitempty"`
	Field2 string `form:"CustomFieldName,omitempty"`
}

Notes

To maximize compatibility with other systems the Encoder attempts to avoid using array indexes in url.Values if at all possible.

eg.

// A struct field of
Field []string{"1", "2", "3"}

// will be output a url.Value as
"Field": []string{"1", "2", "3"}

and not
"Field[0]": []string{"1"}
"Field[1]": []string{"2"}
"Field[2]": []string{"3"}

// however there are times where it is unavoidable, like with pointers
i := int(1)
Field []*string{nil, nil, &i}

// to avoid index 1 and 2 must use index
"Field[2]": []string{"1"}

Benchmarks

Run on MacBook Pro (15-inch, 2017) using go version go1.10.1 darwin/amd64

NOTE: the 1 allocation and B/op in the first 4 decodes is actually the struct allocating when passing it in, so primitives are actually zero allocation.

go test -run=NONE -bench=. -benchmem=true
goos: darwin
goarch: amd64
pkg: github.com/go-playground/form/benchmarks

BenchmarkSimpleUserDecodeStruct-8                                    	 5000000	       236 ns/op	      64 B/op	       1 allocs/op
BenchmarkSimpleUserDecodeStructParallel-8                            	20000000	        82.1 ns/op	      64 B/op	       1 allocs/op
BenchmarkSimpleUserEncodeStruct-8                                    	 2000000	       627 ns/op	     485 B/op	      10 allocs/op
BenchmarkSimpleUserEncodeStructParallel-8                            	10000000	       223 ns/op	     485 B/op	      10 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8                  	 2000000	       724 ns/op	      96 B/op	       1 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8          	10000000	       246 ns/op	      96 B/op	       1 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8                  	  500000	      3187 ns/op	    2977 B/op	      36 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8          	 1000000	      1106 ns/op	    2977 B/op	      36 allocs/op
BenchmarkComplexArrayDecodeStructAllTypes-8                          	  100000	     13748 ns/op	    2248 B/op	     121 allocs/op
BenchmarkComplexArrayDecodeStructAllTypesParallel-8                  	  500000	      4313 ns/op	    2249 B/op	     121 allocs/op
BenchmarkComplexArrayEncodeStructAllTypes-8                          	  200000	     10758 ns/op	    7113 B/op	     104 allocs/op
BenchmarkComplexArrayEncodeStructAllTypesParallel-8                  	  500000	      3532 ns/op	    7113 B/op	     104 allocs/op
BenchmarkComplexMapDecodeStructAllTypes-8                            	  100000	     17644 ns/op	    5305 B/op	     130 allocs/op
BenchmarkComplexMapDecodeStructAllTypesParallel-8                    	  300000	      5470 ns/op	    5308 B/op	     130 allocs/op
BenchmarkComplexMapEncodeStructAllTypes-8                            	  200000	     11155 ns/op	    6971 B/op	     129 allocs/op
BenchmarkComplexMapEncodeStructAllTypesParallel-8                    	  500000	      3768 ns/op	    6971 B/op	     129 allocs/op
BenchmarkDecodeNestedStruct-8                                        	  500000	      2462 ns/op	     384 B/op	      14 allocs/op
BenchmarkDecodeNestedStructParallel-8                                	 2000000	       814 ns/op	     384 B/op	      14 allocs/op
BenchmarkEncodeNestedStruct-8                                        	 1000000	      1483 ns/op	     693 B/op	      16 allocs/op
BenchmarkEncodeNestedStructParallel-8                                	 3000000	       525 ns/op	     693 B/op	      16 allocs/op

Competitor benchmarks can be found here

Complimentary Software

Here is a list of software that compliments using this library post decoding.

  • Validator - Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving.
  • mold - Is a general library to help modify or set data within data structures and other objects.

Package Versioning

I'm jumping on the vendoring bandwagon, you should vendor this package as I will not be creating different version with gopkg.in like allot of my other libraries.

Why? because my time is spread pretty thin maintaining all of the libraries I have + LIFE, it is so freeing not to worry about it and will help me keep pouring out bigger and better things for you the community.

License

Distributed under MIT License, please see license file in code for more details.

Owner
Go Playgound
multiple packages, libraries and programs to further the advancement of Go!
Go Playgound
Comments
  • Option to ignore all struct fields not explicitly tagged via struct tag

    Option to ignore all struct fields not explicitly tagged via struct tag

    In the README there's a section about ignoring fields by tagging them with form:"-". Would it be possible to add an option to the decoder (like SetTagName(tagName string)) to ignore all struct fields not explicitly tagged with form:"fieldName" (or the custom tag name if set)?

    The problem I see is the unintended injection of data because this library is used with user-generated content and accepts form data. Having a language like Go that is strictly typed goes a long way but I do have to go through all of my models and tag them with form:"-". Still, I know this is my fault and want to thank you for this awesome library!

    The reason I'm asking is that I'm also using these structs that are filled with form data to also transform the data for later usage. Sometimes there's additional fields I add that need to be public to use within the app but are not supposed to be accepted via the form data. I'm also always tagging all fields I accept even if the form field's name is the lowercased version of the struct field name (so technically, I wouldn't have to add the struct tag) but you immediately see what's accepted via a form and what's not when looking at the struct definition.

    If this is a request you'd rather not implement then a few pointers on how to make this safer for me or where you'd start looking in the code. :)

  • Add setting use brackets as a namespace separator

    Add setting use brackets as a namespace separator

    Add a new setting that allows using square brackets as a namespace separator.

    In a company I work for we use square brackets as a struct separator.

    • [*] Tests exist or have been written that cover this particular change.

    @go-playground/admins

  • Missing pointer value

    Missing pointer value "0" while encoding struct

    type T struct { X *uint8 form:"x,omitempty" }

    func main() { tx := uint8(0) x := T{&tx} encoder := form.NewEncoder() values, _ := encoder.Encode(x) fmt.Println(values) // blank map }

    If I try to set value to 0, encoder ignores this field

  • CustomTypeFunc is not called when struct contains keys in query

    CustomTypeFunc is not called when struct contains keys in query

    If you have a query of b[0].Foo=1&b[0].Bar=2 and b is a custom struct then my CustomTypeFunc won't be called. However, if the query is b[0]=Foo%3D1%26Bar%3D2 then it works as expected, but I can't expect the caller to know which structs are custom and which aren't.

    Test/example case:

    package main
    
    import (
    	"net/url"
    	"github.com/go-playground/form"
    )
    
    type B struct {
    	C string
    	d interface{}
    }
    
    type A struct {
    	B []B
    }
    
    func main() {
    	d := form.NewDecoder()
    	d.RegisterCustomTypeFunc(func(s []string) (interface{}, error) {
    		b := B{}
    		q, err := url.ParseQuery(s[0])
    		if err != nil {
    			return nil, err
    		}
    		b.C = q.Get("C")
    		if b.C == "foo" {
    			// obviously you could use d.Decode again, but this is an example
    			b.d = struct {
    				E string
    			}{q.Get("E")}
    		}
    		return b, nil
    	}, B{})
    
    	q := url.Values{}
    	q.Set("B[0].C", "foo")
    	q.Set("B[0].E", "bar")
    	a := &A{}
    	d.Decode(a, q)
    	// RegisterCustomTypeFunc is never called
    	// a is &{B:[{C:foo d:<nil>}]}
    
    	q = url.Values{}
    	q.Set("B[0]", "C=foo&E=bar")
    	a = &A{}
    	d.Decode(a, q)
    	// RegisterCustomTypeFunc is called
    	// a is &{B:[{C:foo d:{E:bar}}]}
    }
    
  • Decode form to specific field?

    Decode form to specific field?

    Say I have the following struct:

    type User struct {
     Address Address
    }
    

    Am I able to decode form data to only the Address field? Like so:

    decoder = form.NewDecoder()
    r.ParseForm()
    var user User
    
    if err := decoder.Decode(&user.Address, r.Form); err != nil {
     panic(err)
    }
    

    Assuming the form data provided is in a suitable format for the User struct.

  • Parse string/int into interface{} ?

    Parse string/int into interface{} ?

    Hello,

    I need to support an older version of an API which supported both application/json and application/x-www-form-urlencoded requests, and some of the request parameters had inconsistent types, e.g. it could be sent as a number or a numeric string. So in order to support both json and forms, as well as numeric strings and numbers, I changed the parameter type to interface{}, however, it is always decoded as nil, presumably because the form type and the target value type do not match (e.g. int/string != interface{}), but I would expect that if I have a parameter of type interface{}, and that parameter is found in the form, then it would store the value in the parameter, since it can hold anything.

    Here is an example:

    package main
    
    import (
    	"bytes"
    	"net/url"
    	"fmt"
    	"io"
    	"github.com/go-playground/form"
    )
    
    type V1Request struct {
    	Application interface{} `json:"application"`
    	DeviceModel string      `json:"deviceModel,omitempty"`
    }
    
    func UrlformConsumerFunc() func(reader io.Reader, v interface{}) error {
    	// create a new form decoder
    	decoder := form.NewDecoder()
    
    	// change tag to json since it's added by default by goswagger
    	decoder.SetTagName("json")
    
    	return func(r io.Reader, v interface{}) error {
    		buf := new(bytes.Buffer)
    		buf.ReadFrom(r)
    
    		values, err := url.ParseQuery(buf.String())
    		if err != nil {
    			return err
    		}
    
    		return decoder.Decode(v, values)
    	}
    }
    
    func main() {
    	consumer := UrlformConsumerFunc()
    	req := V1Request{}
    
    	query := bytes.NewBufferString("application=5&deviceModel=iPhone")
    	consumer(query, &req)
    
    	fmt.Printf("Converted value %#v\n", req)
    }
    

    The output of this will be:

    Converted value main.V1Request{Application:interface {}(nil), DeviceModel:"iPhone"}
    

    Is there any way to achieve this using the library?

    Thanks!

  • Custom decoder accepts slice of string but expected to return single item

    Custom decoder accepts slice of string but expected to return single item

    What is the reason to feed custom decoder with slice of strings?

    type DecodeCustomTypeFunc func([]string) (interface{}, error)
    

    Decoder function is called at

    func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx int) (set bool) {
    

    https://github.com/go-playground/form/blob/master/decoder.go#L191

    If target field is a slice, setFieldByType is called in a loop with idx iterating through []string. Internally custom decoder is called with that full []string and without any mention of current idx.

    How decoder function is expected to deal with multi-element input?

    To me it seems correct code should be

    	val, err := cf([]string{arr[idx]})
    

    but then I'm not sure why decoder function needs to accept a slice.

  • Single array param set all elements instead of one

    Single array param set all elements instead of one

    func TestDecodeArrayBug33(t *testing.T) {
    	var data struct {
    		A [3]string
    	}
    	cases := []struct {
    		values url.Values
    		want   [3]string
    	}{
    		{url.Values{"A": {"10"}},
    			[3]string{"10", "", ""}},   // Output: [10 10 10]
    		{url.Values{"A": {"10", "20"}},
    			[3]string{"10", "20", ""}}, // Output: [10 10 10]
    		{url.Values{"A[1]": {"20"}},
    			[3]string{"", "20", ""}},   // Output: [ 20 ]
    		{url.Values{"A": {"10"}, "A[2]": {"30"}},
    			[3]string{"10", "", "30"}}, // Output: [10 10 30]
    	}
    	for _, v := range cases {
    		data.A = [3]string{}
    		form.NewDecoder().Decode(&data, v.values)
    		t.Log(data.A)
    	}
    }
    
  • How to add a new item to a slice?

    How to add a new item to a slice?

    In a HTML form, how do I represent a new (to be added) item for a slice?

    I've tried name="Languages[].Country", where the index isn't defined. As well as providing an index that doesn't exist, neither seem to work.

  • Decode shouldn't panic

    Decode shouldn't panic

    It seems that Decode panics if it receives invalid input. It is not idiomatic go and should be refactored using return errors. Otherwise at least the behaviour should be documented so that the caller can guard it with recover.

  • Starting an array at an arbitrary number is an opportunity for DoS attacks

    Starting an array at an arbitrary number is an opportunity for DoS attacks

    I'm referring to this feature here:

    Array honours the specified index. eg. if "Array[2]" is the only Array value passed down, it will be put at index 2; if array isn't big enough it will be expanded.

    If a user submits a key like Array[1234567890], the application will allocate over 1G of memory just for this single request. Of course, no one is stopping users from putting an even higher number as an index.

    This snippet demonstrates the problem:

    package main
    
    import (
        "log"
        "net/url"
    
        "github.com/go-playground/form"
    )
    
    type A struct {
        Array []int
    }
    
    func main() {
        decoder := form.NewDecoder()
        a := A{}
        err := decoder.Decode(&a, url.Values{"Array[1234567890]": {"42"}})
        if err != nil {
            log.Fatalln(err)
        }
        for {
        }
    }
    

    The RES usage of this application spikes to 1220MB.

  • Multipart form?

    Multipart form?

    Package version eg. v9, v10:

    Issue, Question or Enhancement:

    can you tell me, how can i use this for multipart files??

    Code sample, to showcase or reproduce:

    // Employee
    type Employee struct {
    	Name  string
    	Image *multipart.FileHeader
    }
    
    // Employees
    type Employees struct {
    	Data []Employee
    }
    
    
    {
        "data": [
            {
                "name": "some name1",
                "image": "file1.jpg"
            },
            {
                "name": "some name2",
                "image": "file2.jpg"
            }
        ]
    }
    
    
  • Feature: support

    Feature: support "natural" maps

    It seems that map types are not supported. E.g. map[interface{}]interface{} or map[string]string. Is this the expected behaviour?

    Play

    package main
    
    import (
    	"fmt"
    	"github.com/go-playground/form"
    	"net/url"
    	"reflect"
    )
    
    func main() {
    	dec := form.NewDecoder()
    
    	req := url.Values{"a": []string{"a"}, "b": []string{"b"}, "c": []string{"1"}}
    
    	v := map[interface{}]interface{}{
    		"a": "",
    		"b": "",
    		"c": 0,
    	}
    
    	expected := map[interface{}]interface{}{
    		"a": "a",
    		"b": "b",
    		"c": 1,
    	}
    	if err := dec.Decode(&v, req); err != nil {
    		panic(err)
    	}
    	if !reflect.DeepEqual(v, expected) {
    		fmt.Printf("expected\n %#v\n received\n %#v", expected, v)
    	}
    }
    
    
  • Pointer to int and zero value

    Pointer to int and zero value

    type Request struct {
    	TestInt        *int        `form:"test_int"`
    	TestString  *string   `form:"test_string"`
    }
    

    When providing empty value for "test_string" parameter(r.Form["test_string"]=""), Request.TestString will be not nil and set with the zero value "" as wanted.

    But when "test_int" is provided with an empty string value(r.Form["test_int"]=""), Request.TestInt is still nil and shloud rather be set to the zero value 0.

    It works great with Gorilla Schema

  • map[string]string encode/decode

    map[string]string encode/decode

    fv, _ := form.NewEncoder().Encode(map[string]string{"a": "b"})
    fmt.Printf(`the str="%s"`+"\n", fv.Encode())
    
    the str="%5Ba%5D=b"
    

    i will httpPost(xxx, encodeIt(x))

  • String array should replace the existing one

    String array should replace the existing one

    Example:

    type Form struct {
       Field []string `form:"field"`
    }
    
    form := Form{ Field: []string{"value1", "value2"} }
    
    // vals is contains 'field': "value3", "value4"
    _ := Decoder.Decode(&form, vals)
    
    // form.Field contains now "value1", "value2", "value3", "value4".
    // Excepted was only "value3", "value4"
    

    If I decode the HTTP post values to this struct, the Field property gets appended by the values in the post data instead of replaced.

    The use case is the following: I pre-fill the Form struct with data based on the DB entity. I use this struct also in the view template to render the values. If I would fill the Form struct after the decoding, it will override all the decoded fields if I not check every single field.

    My logical expectation of the form decoder is:

    • If the form field exists in the values, make sure the value match the decoded value (now it's appending string array, don't tested other kind of arrays/struct array)
    • If not just leave the field how it is (works)
  • Incorrectly decode to embedded field

    Incorrectly decode to embedded field

    If same field exists both in parent and embedded struct and url.Values has value only for parent then decoder incorrect set embedded field to same value.

    type Embed struct {
    	A string
    }
    var data struct {
    	A string
    	Embed
    }
    form.NewDecoder().Decode(&data, url.Values{
    	"A": {"one"},
    })
    fmt.Println(data.A, data.Embed.A)
    // Output: one one
    

    If we will add "Embed.A":{"two"} or keep only this one and remove "A": {"one"} then it'll work as expected.

Go module for encoding structs into URL query parameters

qs Package sonh/qs encodes structs into url.Values. Installation go get github.com/sonh/qs Usage import ( "github.com/sonh/qs" ) Package qs export

Jan 7, 2023
Data validation, cleaning and error collection for golang

GoForms - form data validation, cleaning and error reporting The goforms library is a proof-of-concept for a data validation, cleaning and error colle

Jan 14, 2022
Go library for parsing and submitting HTML forms

gosubmit Description Docs are available here: https://godoc.org/github.com/jeremija/gosubmit Helps filling out plain html forms during testing. Will a

Nov 14, 2022
Package gorilla/securecookie encodes and decodes authenticated and optionally encrypted cookie values for Go web applications.

securecookie securecookie encodes and decodes authenticated and optionally encrypted cookie values. Secure cookies can't be forged, because their valu

Dec 26, 2022
Takes an integer array, returns the array sorted and the number of inversions in the array

Takes an integer slice, returns the slice sorted and the number of inversions in the slice

Jan 25, 2022
G-array is a GoLang library, that contains the generic function to do the array operations.

G-array Garray is a library written in Go (Golang). Which have a collection of functions to do the array operations. Installation To install G-array p

Oct 3, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

Jan 6, 2022
The Dual-Stack Dynamic DNS client, the world's first dynamic DNS client built for IPv6.

dsddns DsDDNS is the Dual-Stack Dynamic DNS client. A dynamic DNS client keeps your DNS records in sync with the IP addresses associated with your hom

Sep 27, 2022
Membin is an in-memory database that can be stored on disk. Data model smiliar to key-value but values store as JSON byte array.

Membin Docs | Contributing | License What is Membin? The Membin database system is in-memory database smiliar to key-value databases, target to effici

Jun 3, 2021
:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving

Package validator Package validator implements value validations for structs and individual fields based on tags. It has the following unique features

Jan 1, 2023
💯 Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving

Package validator implements value validations for structs and individual fields based on tags.

Nov 9, 2022
Golang parameter validation, which can replace go-playground/validator, includes ncluding Cross Field, Map, Slice and Array diving, provides readable,flexible, configurable validation.
Golang parameter validation, which can replace go-playground/validator, includes ncluding Cross Field, Map, Slice and Array diving, provides readable,flexible, configurable validation.

Checker 中文版本 Checker is a parameter validation package, can be use in struct/non-struct validation, including cross field validation in struct, elemen

Dec 16, 2022
💪 Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more.
💪 Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more.

?? Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more. Go 的一些工具函数,格式化,特殊处理,常用信息获取等等

Jan 6, 2023
Convert struct, slice, array, map or others for Golang

XConv zh-CN XConv is a golang type convertor. It convert any value between types (base type, struct, array, slice, map, etc.) Features Convert between

Dec 8, 2022
TIled map editor CSV export conversion to C array

tiled2c This tool is very simplistic and is a variation of the one written to convert between Tiled map editor CSV exports and a format for the sega s

Nov 28, 2021
Go library for decoding generic map values into native Go structures and vice versa.

mapstructure mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. This l

Jan 1, 2023
Go library for decoding generic map values into native Go structures and vice versa.

mapstructure mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. This l

Dec 28, 2022
Go library for encoding native Go structures into generic map values.

wstructs origin: github.com/things-go/structs Go library for encoding native Go structures into generic map values. Installation Use go get. go ge

Jan 10, 2022
skipmap is a high-performance concurrent sorted map based on skip list. Up to 3x ~ 10x faster than sync.Map in the typical pattern.
skipmap is a high-performance concurrent sorted map based on skip list. Up to 3x ~ 10x faster than sync.Map in the typical pattern.

Introduction skipmap is a high-performance concurrent map based on skip list. In typical pattern(one million operations, 90%LOAD 9%STORE 1%DELETE), th

Jan 8, 2023
Recursively searches a map[string]interface{} structure for another map[string]interface{} structure

msirecurse Recursively searches a map[string]interface{} structure for existence of a map[string]interface{} structure Motivation I wrote this package

Mar 3, 2022