Skip to main content

coder

Introduced in v0.15.0. For backward compatibility, decoder (introduced in v0.10.0) now is an alias of coder.

coder is a SPECIAL directive executor who overrides the coder that used to encode/decode the value of the corresponding field.

Signature

Name: "coder" | "decoder"
Args: CODER_NAME

When there's a coder directive defined for a field, the specified named decoder will be used rather than the default one which is auto-selected by the type of the field.

Usage

import httpin_core "github.com/ggicci/httpin/core"

type MyDate time.Time // adapted time.Time to MyDate, MyDate must implement httpin_core.Stringable

func (t MyDate) ToString() (string, error) {
return time.Time(t).Format("2006-01-02"), nil
}

func (t *MyDate) FromString(value string) error {
v, err := time.Parse("2006-01-02", value)
if err != nil {
return &InvalidDate{Value: value, Err: err}
}
*t = MyDate(v)
return nil
}

func init() {
// Before using the named coder, you need to register it.
httpin_core.RegisterNamedCoder[time.Time]("date", func(t *time.Time) (httpin_core.Stringable, error) {
return (*MyDate)(t), nil
})
}

type ListUsersInput struct {
Gender string `in:"form=gender"`
// By default, the decoder is auto-selected by the field type, which is of `time.Time`.
// When coder directive is set, the specified named coder "date" will be used instead.
Birthday time.Time `in:"form=birthday;coder=date"`
}

Runable Example

package main

import (
"fmt"
"net/http"
"net/http/httptest"
"time"

"github.com/ggicci/httpin"
httpin_core "github.com/ggicci/httpin/core"
"github.com/justinas/alice"
)

type MyDate time.Time // adapted time.Time to MyDate, MyDate must implement httpin_core.Stringable

func (t MyDate) ToString() (string, error) {
return time.Time(t).Format("2006-01-02"), nil
}

func (t *MyDate) FromString(value string) error {
v, err := time.Parse("2006-01-02", value)
if err != nil {
return fmt.Errorf("invalid date: %w", err)
}
*t = MyDate(v)
return nil
}

func init() {
httpin_core.RegisterNamedCoder[time.Time]("date", func(t *time.Time) (httpin_core.Stringable, error) {
return (*MyDate)(t), nil
})
}

type ListUsersInput struct {
Gender string `in:"form=gender"`
// By default, the decoder is auto-selected by the field type, which is of `time.Time`.
// When decoder directive is set, the specified named decoder "date" will be used instead.
Birthday time.Time `in:"form=birthday;coder=date"`
}

func ListUsers(rw http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*ListUsersInput)
fmt.Printf("input: %#v\n", input)
}

func main() {
mux := http.NewServeMux()
mux.Handle("/users", alice.New(
httpin.NewInput(ListUsersInput{}),
).ThenFunc(ListUsers))

r, _ := http.NewRequest("GET", "/users?gender=male&birthday=1991-11-10", nil)
rw := httptest.NewRecorder()
mux.ServeHTTP(rw, r)
}