formam

package module
Version: v3.5.5+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2021 License: Apache-2.0 Imports: 9 Imported by: 66

README

formam

A Go package to decode HTTP form and query parameters. The only requirement is Go 1.12 or later.

Build Status GoDoc

Install

go get github.com/monoculum/formam/v3

Features

  • Infinite nesting for maps, structs and slices.
  • Support UnmarshalText() interface in values and keys of maps.
  • Supported map keys are string, int and variants, uint and variants, uintptr, float32, float64, bool, struct, custom types to one of the above types registered by function or UnmarshalText method, a pointer to one of the above types
  • A field with interface{} that has a map, struct or slice as value is accessible.
  • Decode time.Time with format 2006-01-02 by its UnmarshalText() method.
  • Decode url.URL.
  • Append to slice and array types without explicitly indicating an index.
  • Register a function for a custom type.

Performance

You can see the performance in formam-benchmark compared with ajg/form, gorilla/schema, go-playground/form and built-in/json.

Basic usage example

In form HTML
  • Use . to access a struct field (e.g. struct.field1).
  • Use [<index>] to access tje specific slice/array index (e.g. struct.array[0]). It's not necessary to add an index to append data.
  • Use [<key>] to access map keys (e.g.. struct.map[es-ES]).
<form method="POST">
  <input type="text" name="Name" value="Sony" />
  <input type="text" name="Location.Country" value="Japan" />
  <input type="text" name="Location.City" value="Tokyo" />
  <input type="text" name="Products[0].Name" value="Playstation 4" />
  <input type="text" name="Products[0].Type" value="Video games" />
  <input type="text" name="Products[1].Name" value="TV Bravia 32" />
  <input type="text" name="Products[1].Type" value="TVs" />
  <input type="text" name="Founders[0]" value="Masaru Ibuka" />
  <input type="text" name="Founders[0]" value="Akio Morita" />
  <input type="text" name="Employees" value="90000" />
  <input type="text" name="public" value="true" />
  <input type="url" name="website" value="http://www.sony.net" />
  <input type="date" name="foundation" value="1946-05-07" />
  <input type="text" name="Interface.ID" value="12" />
  <input type="text" name="Interface.Name" value="Go Programming Language" />
  <input type="submit" />
</form>
In Go

You can use the formam struct tag to ensure the form values are unmarshalled in the currect struct fields.

type InterfaceStruct struct {
    ID   int
    Name string
}

type Company struct {
  Public     bool      `formam:"public"`
  Website    url.URL   `formam:"website"`
  Foundation time.Time `formam:"foundation"`
  Name       string
  Location   struct {
    Country  string
    City     string
  }
  Products   []struct {
    Name string
    Type string
  }
  Founders   []string
  Employees  int64

  Interface interface{}
}

func MyHandler(w http.ResponseWriter, r *http.Request) error {
  r.ParseForm()

  m := Company{
      // it's is possible to access to the fields although it's an interface field!
      Interface: &InterfaceStruct{},
  }
  dec := formam.NewDecoder(&formam.DecoderOptions{TagName: "formam"})
  return dec.Decode(r.Form, &m)
}

Types

Supported types in the destination struct are:

  • string
  • bool
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • slice, array
  • struct and struct anonymous
  • map
  • interface{}
  • time.Time
  • url.URL
  • custom types to one of the above types
  • a pointer to one of the above types

Custom Marshaling

You can umarshal data and map keys by implementing the encoding.TextUnmarshaler interface.

If the forms sends multiple values then only the first value is passed to UnmarshalText(), but if the name ends with [] then it's called for all values.

Custom Type

You can register a function for a custom type using the RegisterCustomType() method. This will work for any number of given fields or all fields with the given type.

Registered type have preference over the UnmarshalText method unless the PrefUnmarshalText option is used.

All fields
decoder.RegisterCustomType(func(vals []string) (interface{}, error) {
        return time.Parse("2006-01-02", vals[0])
}, []interface{}{time.Time{}}, nil)
Specific fields
package main

type Times struct {
    Timestamp   time.Time
    Time        time.Time
    TimeDefault time.Time
}

func main() {
    var t Timestamp

    dec := NewDecoder(nil)

    // for Timestamp field
    dec.RegisterCustomType(func(vals []string) (interface{}, error) {
            return time.Parse("2006-01-02T15:04:05Z07:00", vals[0])
    }, []interface{}{time.Time{}}, []interface{}{&t.Timestamp{}})

    // for Time field
    dec.RegisterCustomType(func(vals []string) (interface{}, error) {
                return time.Parse("Mon, 02 Jan 2006 15:04:05 MST", vals[0])
    }, []interface{}{time.Time{}}, []interface{}{&t.Time{}})

    // for field that not be Time or Timestamp, e.g. in this example, TimeDefault.
    dec.RegisterCustomType(func(vals []string) (interface{}, error) {
                return time.Parse("2006-01-02", vals[0])
    }, []interface{}{time.Time{}}, nil)

    dec.Decode(url.Values{}, &t)
}

Notes

Version 2 is compatible with old syntax to access to maps (map.key), but brackets are the preferred way to access a map (map[key]).

Documentation

Overview

Package formam decodes HTTP form and query parameters.

Index

Constants

View Source
const (
	ErrCodeNotAPointer  uint8 = iota // Didn't pass a pointer to Decode().
	ErrCodeArrayIndex                // Error attempting to use an array index (e.g. foo[2]).
	ErrCodeConversion                // Error converting field to the type.
	ErrCodeUnknownType               // Unknown type.
	ErrCodeUnknownField              // No struct field for passed parameter (will never be used if IgnoreUnknownKeys is set).
	ErrCodeRange                     // Number is out of range (e.g. parsing 300 in uint8 would overflow).
	ErrCodeArraySize                 // Array longer than MaxSize.
)

Error codes.

Variables

This section is empty.

Functions

func Decode

func Decode(vs url.Values, dst interface{}) error

Decode the url.Values and populate the destination dst, which must be a pointer.

Types

type DecodeCustomTypeFunc

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

DecodeCustomTypeFunc for decoding a custom type.

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder to decode a form.

func NewDecoder

func NewDecoder(opts *DecoderOptions) *Decoder

NewDecoder creates a new instance of Decoder.

func (Decoder) Decode

func (dec Decoder) Decode(vs url.Values, dst interface{}) error

Decode the url.Values and populate the destination dst, which must be a pointer.

func (*Decoder) RegisterCustomType

func (dec *Decoder) RegisterCustomType(fn DecodeCustomTypeFunc, types []interface{}, fields []interface{}) *Decoder

RegisterCustomType registers a functions for decoding custom types.

type DecoderOptions

type DecoderOptions struct {
	// Struct field tag name; default is "formam".
	TagName string

	// Prefer UnmarshalText over custom types.
	PrefUnmarshalText bool

	// Disable UnmarshalText interface
	DisableUnmarshalText bool

	// Ignore unknown form fields. By default unknown fields are an error
	// (although all valid keys will still be decoded).
	IgnoreUnknownKeys bool

	// The maximum array size that formam will create. This is limited to
	// prevent malicious input to create huge arrays to starve the server of
	// memory.
	//
	// The default is 16,000; set to -1 to disable.
	MaxSize int
}

DecoderOptions options for decoding the values.

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error indicates a error produced

func (*Error) Cause

func (s *Error) Cause() error

Cause implements the causer interface from github.com/pkg/errors.

func (Error) Code

func (s Error) Code() uint8

Code for this error. See the ErrCode* constants.

func (*Error) Error

func (s *Error) Error() string

func (Error) MarshalJSON

func (s Error) MarshalJSON() ([]byte, error)

MarshalJSON implements the interface Marshaler

func (Error) Path

func (s Error) Path() string

Path for this error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL