form

package module
v1.9.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: BSD-3-Clause Imports: 11 Imported by: 216

README

form

A Form Encoding & Decoding Package for Go, written by Alvaro J. Genial.

Build Status Go Reference

Synopsis

This library is designed to allow seamless, high-fidelity encoding and decoding of arbitrary data in application/x-www-form-urlencoded format and as url.Values. It is intended to be useful primarily in dealing with web forms and URI query strings, both of which natively employ said format.

Unsurprisingly, form is modeled after other Go encoding packages, in particular encoding/json, and follows the same conventions (see below for more.) It aims to automatically handle any kind of concrete Go data value (i.e., not functions, channels, etc.) while providing mechanisms for custom behavior.

Status

form is stable and in production use. The public API and the wire format are settled: within the v1 series they will not change incompatibly, and anything that would require a breaking change is deferred to a future v2 (see Future Work).

The package is thoroughly tested — an extensive unit suite, end-to-end HTTP tests, and a native fuzz target seeded from past bugs — and has been hardened against the resource-exhaustion and malformed-input classes: bounded slice growth, nesting depth, and raw input size, with typed, classified errors on every decode path. It has not undergone a formal third-party security audit, so give untrusted input the usual care and set the available limits. Please file an issue or open a pull request for anything you find (see CONTRIBUTING and SECURITY).

Dependencies

The only requirement is Go 1.17 or later.

Usage

import "github.com/ajg/form"
// or: "gopkg.in/ajg/form.v1"

Given a type like the following...

type User struct {
	Name         string            `form:"name"`
	Email        string            `form:"email"`
	Joined       time.Time         `form:"joined,omitempty"`
	Posts        []int             `form:"posts"`
	Preferences  map[string]string `form:"prefs"`
	Avatar       []byte            `form:"avatar"`
	PasswordHash int64             `form:"-"`
}

...it is easy to encode data of that type...

func PostUser(url string, u User) error {
	var c http.Client
	_, err := c.PostForm(url, form.EncodeToValues(u))
	return err
}

...as well as decode it...

func Handler(w http.ResponseWriter, r *http.Request) {
	var u User

	d := form.NewDecoder(r.Body)
	if err := d.Decode(&u); err != nil {
		http.Error(w, "Form could not be decoded", http.StatusBadRequest)
		return
	}

	fmt.Fprintf(w, "Decoded: %#v", u)
}

...without having to do any grunt work.

Field Tags

Like other encoding packages, form supports the following options for fields:

  • `form:"-"`: Causes the field to be ignored during encoding and decoding.
  • `form:"<name>"`: Overrides the field's name; useful especially when dealing with external identifiers in camelCase, as are commonly found on the web.
  • `form:",omitempty"`: Elides the field during encoding if it is empty (typically meaning equal to the type's zero value.)
  • `form:"<name>,omitempty"`: The way to combine the two options above.

When a field carries no form tag, a json tag, if present, is used in its place — convenient for structs already annotated for JSON APIs. (The form/multipart subpackage follows the same rule.)

Values

Simple Values

Values of the following types are all considered simple:

  • bool
  • int, int8, int16, int32, int64, rune
  • uint, uint8, uint16, uint32, uint64, byte
  • float32, float64
  • complex64, complex128
  • string
  • []byte (see note)
  • time.Time
  • url.URL
  • The fixed-channel image/color types when represented as hex strings (see Colors; unlike time.Time and url.URL these are dual-representation — their composite form below also remains supported, and is the default when encoding)
  • An alias of any of the above
  • A pointer to any of the above
Composite Values

A composite value is one that can contain other values. Values of the following kinds...

  • Maps
  • Slices; except []byte (see note)
  • Structs; except time.Time, url.URL and — when written as hex strings — the fixed-channel color types (see Colors)
  • Arrays
  • An alias of any of the above
  • A pointer to any of the above

...are considered composites in general, unless they implement custom marshaling/unmarshaling. Composite values are encoded as a flat mapping of paths to values, where the paths are constructed by joining the parent and child paths with a period (.).

(Note: a byte slice is treated as a string by default because it's more efficient, but can also be decoded as a slice—i.e., with indexes.)

Untyped Values

While encouraged, it is not necessary to define a type (e.g. a struct) in order to use form, since it is able to encode and decode untyped data generically using the following rules:

  • Simple values will be treated as a string.
  • Because application/x-www-form-urlencoded carries no type information, no numeric (or other) interpretation is attempted: simple values are preserved as strings exactly as sent, so numerals of any magnitude — including those exceeding Go's primitive types — survive losslessly, and the caller decides how, and at what precision, to parse them.
  • Composite values will be treated as a map[string]interface{}, itself able to contain nested values (both simple and composite) ad infinitum.
  • However, if there is a value (of any supported type) already present in a map for a given key, then it will be used when possible, rather than being replaced with a generic value as specified above; this makes it possible to handle partially typed, dynamic or schema-less values.
Zero Values

By default, and without custom marshaling, zero values (also known as empty/default values) are encoded as the empty string. To disable this behavior, meaning to keep zero values in their literal form (e.g. 0 for integral types), Encoder offers a KeepZeros setter method, which will do just that when set to true.

For instance, given...

foo := map[string]interface{}{"b": false, "i": 0}

...the following...

form.EncodeToString(foo) // i.e. keepZeros == false

...will result in "b=&i=", whereas...

keepZeros := true
delimiter := '.'
escape := '\\'
form.EncodeToStringWith(foo, delimiter, escape, keepZeros)

...will result in "b=false&i=0".

Unsupported Values

Values of the following kinds aren't supported and, if present, must be ignored.

  • Channel
  • Function
  • Unsafe pointer
  • An alias of any of the above
  • A pointer to any of the above
Colors

The fixed-channel image/color types (NRGBA, RGBA, NRGBA64, RGBA64, Gray, Gray16, Alpha, Alpha16 and CMYK) decode from hex strings such as those submitted by HTML <input type=color> elements — bare or #-prefixed, case-insensitive, with CSS-style shorthand (f00, f00a) accepted by the 8-bit RGBA types and an omitted alpha defaulting to opaque. The encoding is byte-faithful per type, so every value round-trips exactly; accordingly, the premultiplied types (RGBA, RGBA64) reject values whose color channels exceed their alpha — that shape almost always means straight-alpha (CSS) semantics, for which NRGBA/NRGBA64 are the faithful destinations.

The pre-existing composite representation (c.R=255&c.G=0&…) continues to decode for every color type, and remains the default encoding; opt into hex output with Encoder.HexColors(true). Named types based on the color types keep the composite representation entirely.

Custom Marshaling

There is a default (generally lossless) marshaling & unmarshaling scheme for any concrete data value in Go, which is good enough in most cases. However, it is possible to override it and use a custom scheme. For instance, a "binary" field could be marshaled more efficiently using base64 to prevent it from being percent-escaped during serialization to application/x-www-form-urlencoded format.

Because form provides support for encoding.TextMarshaler and encoding.TextUnmarshaler it is easy to do that; for instance, like this:

import "encoding"

type Binary []byte

var (
	_ encoding.TextMarshaler   = &Binary{}
	_ encoding.TextUnmarshaler = &Binary{}
)

func (b Binary) MarshalText() ([]byte, error) {
	return []byte(base64.URLEncoding.EncodeToString([]byte(b))), nil
}

func (b *Binary) UnmarshalText(text []byte) error {
	bs, err := base64.URLEncoding.DecodeString(string(text))
	if err == nil {
		*b = Binary(bs)
	}
	return err
}

Now any value with type Binary will automatically be encoded using the URL variant of base64. It is left as an exercise to the reader to improve upon this scheme by eliminating the need for padding (which, besides being superfluous, uses =, a character that will end up percent-escaped.)

Standard-library types that implement these interfaces work out of the box. Notably, that includes math/big: Int and Rat encode and decode losslessly at arbitrary precision, and Float at its destination's precision — a 64-bit mantissa by default (already wider than float64), or any precision pre-set on the destination value with SetPrec before decoding. These are the natural destinations for numeric values too large for Go's primitive types; decoding an out-of-range value into a primitive fails loudly rather than truncating silently.

Keys

In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to form, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (\). Backslashes within keys, themselves, are also escaped in this manner (e.g. as \\) in order to permit representing \. itself (as \\\.).

(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.)

The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the DelimitWith and EscapeWith setter methods of Encoder and Decoder, respectively. For example...

package main

import (
	"os"

	"github.com/ajg/form"
)

func main() {
	type B struct {
		Qux string `form:"qux"`
	}
	type A struct {
		FooBar B `form:"foo.bar"`
	}
	a := A{FooBar: B{"XYZ"}}
	os.Stdout.WriteString("Default: ")
	form.NewEncoder(os.Stdout).Encode(a)
	os.Stdout.WriteString("\nCustom:  ")
	form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a)
	os.Stdout.WriteString("\n")
}

...will produce...

Default: foo%5C.bar.qux=XYZ
Custom:  foo.bar%2Fqux=XYZ

(%5C and %2F represent \ and /, respectively.)

Key Mapping

When a wire naming convention differs from Go's — snake_case being the usual case — KeysWith on both Decoder and Encoder sets a transformation applied to struct field names, at every nesting level, to obtain their form keys:

form.NewDecoder(r).KeysWith(strcase.ToSnake) // or any func(string) string

Fields with an explicit tag are exempt — tags always name keys verbatim — and the same function should be set on both directions for values to round-trip; passing nil clears the mapping. The function receives struct field names only, never input data; it should be deterministic and injective — distinct fields must map to distinct keys, including any explicitly tagged names — should avoid emitting the reserved implicit-index key _ or the delimiter rune, and — since decoding may invoke it once per candidate field per incoming key — memoize it if it is expensive. form deliberately ships no built-in casing heuristic: word-boundary rules (acronyms, digits) are project-specific, and baking one in would freeze its inevitable edge cases into the wire format. Bring your own mapper and it is applied mechanically.

Unknown Keys and Case

Decoding is strict by default: a key that matches no field in the destination is an error. Decoder.IgnoreUnknownKeys(true) makes the decoder skip such values instead — the pragmatic choice for raw browser submissions, which routinely carry fields the destination doesn't model (CSRF tokens, submit-button names). Separately, Decoder.IgnoreCase(true) lets keys match fields even when their cases differ.

Limits

When decoding untrusted input, the Decoder bounds two dimensions to prevent resource-exhaustion denial of service (added in v1.7.2):

  • Slice size. An explicit index such as Foo.1000000=x will not pre-allocate an unbounded slice. By default the allowed length is proportional to the number of elements actually supplied, so ordinary data is unaffected while a tiny payload with a huge index is rejected. Override with Decoder.MaxSize(n): n > 0 sets a fixed cap, n < 0 disables the bound (trusted input only), and the zero value keeps the proportional default.

  • Key-path depth. A key with many delimiters such as a.a.a.…=x is rejected past a maximum nesting depth (default 10000, far beyond any real form). Override with Decoder.MaxDepth(n): n > 0 sets the limit, n < 0 disables it (trusted input only), and the zero value keeps the default.

  • Input size. Decode reads its entire input into memory before parsing. For untrusted streams, bound it with Decoder.MaxBytes(n) (a larger input is rejected) or wrap the reader (e.g. with http.MaxBytesReader). Unlike the bounds above, this one is off by default, because a built-in cap would break legitimately large trusted inputs; set it explicitly when decoding untrusted data.

The package-level DecodeString and DecodeValues helpers use these safe defaults. If you decode large but trusted input and hit a limit, raise or disable it via the methods above.

Errors

Errors returned by the decoding and encoding functions are of type *form.Error, which records the operation that failed via Op (form.OpDecode or form.OpEncode), the class of failure via Kind (form.KindParse, form.KindUnknownKey, form.KindLimit, and so on; the zero value means unclassified), and, through errors.Unwrap, any underlying cause — such as an error from a TextMarshaler/TextUnmarshaler or a malformed-query error from the standard library. Detect and inspect them with errors.As and errors.Is. The message text returned by Error is unchanged from earlier versions, so code that matches on error strings continues to work.

File Uploads (multipart/form-data)

HTML forms that contain file inputs submit multipart/form-data rather than application/x-www-form-urlencoded; the subpackage form/multipart decodes such submissions into structs. Value fields follow the same rules as this package (field tags, nesting, custom delimiters, the limits above), while file parts are matched by name onto fields declared as any of *multipart.FileHeader, []*multipart.FileHeader, []byte, or [][]byte:

import (
	"mime/multipart"

	fmp "github.com/ajg/form/multipart"
)

type Upload struct {
	Name   string                  `form:"name"`
	Avatar *multipart.FileHeader   `form:"avatar"` // Lazy: open/stream/close it yourself.
	Docs   [][]byte                `form:"docs"`   // Eager: read into memory during decoding.
}

func handle(w http.ResponseWriter, r *http.Request) {
	var u Upload
	if err := fmp.DecodeRequest(&u, r, 32<<20); err != nil { // Calls r.ParseMultipartForm.
		// ...
	}
	// ...
}
  • The *multipart.FileHeader forms hand over the standard library's own handle: the caller Opens (and closes) the file and may stream it, so no size bound is imposed by this package.
  • The []byte forms are read into memory during decoding, bounded by Decoder.MaxFileSize (10 MiB per file by default) and Decoder.MaxFiles (1000 per key by default), which follow the same zero/positive/negative convention as the limits above.

Like this package, decoding is strict by default: a value or file key that matches no destination field is an error. Browser submissions routinely carry extra fields (CSRF tokens, submit-button names); either model them or skip them with fmp.NewDecoder().IgnoreUnknownKeys(true).

Future Work

Remaining aspirations are deliberately deferred to a future v2, where some defaults may change: decoding is expected to become lenient about unknown keys by default (with strictness opt-in), hex is expected to become the default encoding for the fixed-channel image/color types, and slice wire-format conventions (such as PHP/Rails-style services[]=… or bare repeated keys) are candidates for an implicit-indexing rework. The longest-standing item — streaming encoding and decoding directly via the io.Reader/io.Writer instead of materializing the input, its url.Values and an intermediate tree in memory — is likewise v2-shaped: implicit indexing and the deterministic handling of conflicting keys are whole-input properties that a streaming design must either restrict or redefine.

License

This library is distributed under a BSD-style LICENSE.

Documentation

Overview

Package form implements encoding and decoding of application/x-www-form-urlencoded data.

Errors returned by the Decode and Encode functions are of type *Error, which records the operation (Op) that failed and, via Unwrap, any underlying cause such as an error from a TextMarshaler or TextUnmarshaler. Use errors.As to inspect them; the Error message text is unchanged from earlier versions.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DecodeString

func DecodeString(dst interface{}, src string) error

DecodeString decodes src into dst.

Example
package main

import (
	"fmt"

	"github.com/ajg/form"
)

func main() {
	type profile struct {
		Name string   `form:"name"`
		Age  int      `form:"age"`
		Tags []string `form:"tags"`
	}
	var p profile
	if err := form.DecodeString(&p, "name=Alice&age=30&tags.0=go&tags.1=forms"); err != nil {
		panic(err)
	}
	fmt.Printf("%s is %d; tags=%v", p.Name, p.Age, p.Tags)
}
Output:
Alice is 30; tags=[go forms]

func DecodeValues

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

DecodeValues decodes vs into dst.

func EncodeToString

func EncodeToString(dst interface{}, needEmptyValue ...bool) (string, error)

EncodeToString encodes dst as a form and returns it as a string.

Example
package main

import (
	"fmt"

	"github.com/ajg/form"
)

func main() {
	type profile struct {
		Name string `form:"name"`
		Age  int    `form:"age"`
	}
	// Keys come out sorted, so encoding is deterministic.
	s, err := form.EncodeToString(&profile{Name: "Alice", Age: 30})
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}
Output:
age=30&name=Alice

func EncodeToStringWith added in v1.7.0

func EncodeToStringWith(dst interface{}, d rune, e rune, z bool) (string, error)

EncodeToStringWith encodes dst as a form with delimiter d, escape e, keeping zero values if z, and returns it as a string. The delimiter and escape must differ.

func EncodeToValues

func EncodeToValues(dst interface{}, needEmptyValue ...bool) (url.Values, error)

EncodeToValues encodes dst as a form and returns it as Values.

func EncodeToValuesWith added in v1.7.0

func EncodeToValuesWith(dst interface{}, d rune, e rune, z bool) (url.Values, error)

EncodeToValuesWith encodes dst as a form with delimiter d, escape e, keeping zero values if z, and returns it as Values. The delimiter and escape must differ.

Types

type Decoder

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

Decoder decodes data from a form (application/x-www-form-urlencoded).

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ajg/form"
)

func main() {
	// Decode directly from any io.Reader — e.g. an HTTP request body.
	// Nested keys use dotted paths.
	type request struct {
		User struct {
			Name string `form:"name"`
			Age  int    `form:"age"`
		} `form:"user"`
	}
	var req request
	if err := form.NewDecoder(strings.NewReader("user.name=Bob&user.age=42")).Decode(&req); err != nil {
		panic(err)
	}
	fmt.Printf("%+v", req)
}
Output:
{User:{Name:Bob Age:42}}

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new form Decoder.

func (Decoder) Decode

func (d Decoder) Decode(dst interface{}) error

Decode reads in and decodes form-encoded data into dst.

func (Decoder) DecodeString

func (d Decoder) DecodeString(dst interface{}, src string) error

DecodeString decodes src into dst.

func (Decoder) DecodeValues

func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error

DecodeValues decodes vs into dst.

func (*Decoder) DelimitWith

func (d *Decoder) DelimitWith(r rune) *Decoder

DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default. The delimiter must differ from the escape (validated when decoding) and should not occur unescaped within keys.

func (*Decoder) EscapeWith

func (d *Decoder) EscapeWith(r rune) *Decoder

EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default. The escape must differ from the delimiter (validated when decoding).

func (*Decoder) IgnoreCase

func (d *Decoder) IgnoreCase(ignoreCase bool)

IgnoreCase if set to true it will make the Decoder try to set values in the destination object even if the case does not match.

func (*Decoder) IgnoreUnknownKeys

func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool)

IgnoreUnknownKeys if set to true it will make the Decoder ignore values that are not found in the destination object instead of returning an error.

func (*Decoder) KeysWith added in v1.9.0

func (d *Decoder) KeysWith(f func(string) string) *Decoder

KeysWith sets f as a transformation applied to struct field names — at every nesting level — to obtain their form keys, and returns the Decoder. Fields with an explicit tag are exempt: tags always name keys verbatim. Use it to map Go naming to a wire convention, e.g. snake_case:

d.KeysWith(strcase.ToSnake) // or any func(string) string

Passing nil clears the transformation, restoring default field-name matching. f is only ever called with struct field names — never with input data — and must be deterministic, return non-empty keys, and be injective over a struct's field names, tagged ones included: unstable or colliding outputs yield unspecified (though safe) matching. Outputs should avoid the reserved implicit-index key "_" and the delimiter rune (a delimiter within a mapped name is escaped on the wire, which other consumers may not expect). A panic inside f is recovered into a *Error like any other decoding failure.

The same transformation should be set on the Encoder (see Encoder.KeysWith) for values to round-trip. Configure IgnoreCase separately if case-insensitive matching of the transformed keys is also desired.

func (*Decoder) MaxBytes added in v1.9.0

func (d *Decoder) MaxBytes(maxBytes int64) *Decoder

MaxBytes bounds how many bytes of input Decode will read into memory before parsing, guarding against memory exhaustion from an oversized payload. A value > 0 sets the bound; a larger input yields a KindLimit error. Values <= 0 leave input unbounded — the default, for compatibility; bound untrusted streams explicitly here or by wrapping the reader (e.g. with http.MaxBytesReader). It applies only to Decode: DecodeString and DecodeValues receive already-materialized input.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/ajg/form"
)

func main() {
	// Bound how much raw input a Decoder will buffer from an untrusted
	// stream; oversized input fails instead of being read into memory.
	var m map[string]string
	oversized := "a=" + strings.Repeat("x", 1000)
	err := form.NewDecoder(strings.NewReader(oversized)).MaxBytes(32).Decode(&m)
	fmt.Println(err != nil)
}
Output:
true

func (*Decoder) MaxDepth added in v1.7.2

func (d *Decoder) MaxDepth(maxDepth int) *Decoder

MaxDepth overrides the maximum key-path nesting depth the Decoder will parse, guarding against stack exhaustion and nested-map blow-up from a single key with many delimiters (e.g. "a.a.a.…=x"). Legitimate nesting is bounded by the destination type, so the default sits far above any real form. A value > 0 sets the limit; a value < 0 disables it (trusted input only); the zero value uses the built-in default.

func (*Decoder) MaxSize added in v1.7.2

func (d *Decoder) MaxSize(maxSize int) *Decoder

MaxSize overrides how large a slice the Decoder will grow in response to an explicit index in the input, guarding against memory exhaustion from a small payload with a very large index (e.g. "Foo.900000000=x").

By default (the zero value) the Decoder uses a bound proportional to the number of elements actually supplied, so legitimately large slices decode while amplification is prevented; most callers never need this method. A value > 0 sets a fixed absolute cap instead (use a large value to permit large sparse slices in trusted input, or a small one to tighten the limit). A value < 0 disables the bound entirely; only do this for fully trusted input.

func (*Decoder) Reset added in v1.9.0

func (d *Decoder) Reset(r io.Reader) *Decoder

Reset switches the Decoder to read from r, retaining all other configuration, and returns the Decoder. It allows a configured Decoder to be reused (e.g. via sync.Pool) without reallocation.

type Encoder

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

Encoder provides a way to encode to a Writer.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new form Encoder.

func (*Encoder) DelimitWith

func (e *Encoder) DelimitWith(r rune) *Encoder

DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default. The delimiter must differ from the escape (validated when encoding).

func (Encoder) Encode

func (e Encoder) Encode(dst interface{}) error

Encode encodes dst as form and writes it out using the Encoder's Writer.

func (*Encoder) EscapeWith

func (e *Encoder) EscapeWith(r rune) *Encoder

EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default. The escape must differ from the delimiter (validated when encoding).

func (*Encoder) HexColors added in v1.9.0

func (e *Encoder) HexColors(h bool) *Encoder

HexColors makes the Encoder render the fixed-channel image/color types as bare lowercase hex strings (e.g. color.NRGBA => "ff007f80"; see color.go for the per-type formats) instead of as composite structs (C.R=255&C.G=0&…). It is false by default, preserving the existing composite wire format for current consumers. Decoding accepts both representations regardless.

func (*Encoder) KeepZeros

func (e *Encoder) KeepZeros(z bool) *Encoder

KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string.

func (*Encoder) KeysWith added in v1.9.0

func (e *Encoder) KeysWith(f func(string) string) *Encoder

KeysWith sets f as a transformation applied to struct field names — at every nesting level — to obtain their form keys, and returns the Encoder. Fields with an explicit tag are exempt: tags always name keys verbatim. Passing nil clears the transformation. f is only ever called with struct field names — never with data being encoded — and must be deterministic, return non-empty keys, and be injective over a struct's field names, tagged ones included; colliding outputs yield an unspecified (though safe) result, and outputs should avoid the reserved implicit-index key "_" and the delimiter rune. A panic inside f is recovered into a *Error. Set the same transformation on the Decoder (see Decoder.KeysWith) for values to round-trip.

func (*Encoder) OmitEmpty added in v1.6.1

func (e *Encoder) OmitEmpty(o bool) *Encoder

OmitEmpty sets whether Encoder e should omit empty (zero) struct fields during encoding, and returns the former; this is equivalent to having ",omitempty" on every field. By default, empty fields are included.

func (*Encoder) Reset added in v1.9.0

func (e *Encoder) Reset(w io.Writer) *Encoder

Reset switches the Encoder to write to w, retaining all other configuration, and returns the Encoder. It allows a configured Encoder to be reused (e.g. via sync.Pool) without reallocation.

type Error added in v1.8.0

type Error struct {
	Op   Op    // the operation that failed
	Kind Kind  // the class of failure; empty when unclassified
	Err  error // the underlying cause, if any; nil when the message originates here
	// contains filtered or unexported fields
}

Error is the error type returned by Decode and Encode operations for malformed input or values that cannot be represented. Callers can use errors.As to detect it and inspect Op and Kind, and errors.Unwrap (via Err) to reach an underlying cause such as an error from a TextMarshaler or TextUnmarshaler.

The text returned by the Error method is identical to that of earlier versions, so code matching on error strings is unaffected.

func NewError added in v1.9.0

func NewError(op Op, kind Kind, err error, msg string) *Error

NewError returns an *Error with the given operation, kind, underlying cause (which may be nil) and message. It exists so that packages built on top of form (such as form/multipart) can return errors that participate in the same errors.As taxonomy.

func NewErrorf added in v1.9.0

func NewErrorf(op Op, kind Kind, err error, format string, args ...interface{}) *Error

NewErrorf is NewError with fmt.Errorf-style message formatting. Like NewError it exists for packages built on top of form; the formatting is performed eagerly, exactly as a fmt.Sprintf at the call site would be.

func (*Error) Error added in v1.8.0

func (e *Error) Error() string

Error returns the error message.

func (*Error) Unwrap added in v1.8.0

func (e *Error) Unwrap() error

Unwrap returns the underlying cause, enabling errors.Is and errors.As.

type Kind added in v1.9.0

type Kind string

Kind classifies the failure that produced an Error. The zero value means the failure is unclassified — typically an error propagated from a custom TextMarshaler/TextUnmarshaler or another external source; use Unwrap (via errors.As/Is) to reach the cause.

const (
	// KindSyntax reports input that is not well-formed
	// application/x-www-form-urlencoded data.
	KindSyntax Kind = "syntax"

	// KindParse reports a value that cannot be parsed as the destination
	// type (e.g. "abc" into an int, or an invalid time).
	KindParse Kind = "parse"

	// KindUnknownKey reports a key with no corresponding destination field;
	// see Decoder.IgnoreUnknownKeys.
	KindUnknownKey Kind = "unknown-key"

	// KindIndex reports an explicit index that is not a valid position in
	// the destination (malformed, negative, or beyond an array's bounds).
	KindIndex Kind = "index"

	// KindLimit reports input that exceeds a decoder resource bound; see
	// Decoder.MaxSize and Decoder.MaxDepth.
	KindLimit Kind = "limit"

	// KindUnsupported reports a destination or value that cannot be
	// represented as form data (an unsupported kind, an unsettable field, or
	// an invalid destination).
	KindUnsupported Kind = "unsupported"

	// KindCycle reports a self-referential value encountered while encoding.
	KindCycle Kind = "cycle"

	// KindIO reports a failure reading input or writing encoded output.
	KindIO Kind = "io"
)

type Op added in v1.8.0

type Op string

Op identifies the operation that produced an Error.

const (
	OpDecode Op = "decode"
	OpEncode Op = "encode"
)

Directories

Path Synopsis
Package multipart decodes multipart/form-data — as submitted by HTML forms containing file inputs — into Go structs, using github.com/ajg/form to decode the value fields and mapping file parts onto struct fields by name.
Package multipart decodes multipart/form-data — as submitted by HTML forms containing file inputs — into Go structs, using github.com/ajg/form to decode the value fields and mapping file parts onto struct fields by name.

Jump to

Keyboard shortcuts

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