Skip to content

Guide

Customization

Replace Zinc's error handler, validator, renderer, JSON codec, or request binder with your own.

Each part of Zinc that makes a policy decision can be replaced through configuration: how errors are written, how input is validated, how JSON is encoded, how templates render. Each extension point is a small interface, so a replacement is usually a few lines.

cfg := zinc.DefaultConfig
cfg.ErrorHandler = writeJSONError
cfg.Validator = structValidator{v: validator.New()}
cfg.JSONCodec = sonicCodec{}
cfg.Renderer = zinc.NewHTMLTemplateRenderer(views)
app := zinc.NewWithConfig(cfg)
type ErrorHandler func(c *zinc.Context, err error)

Called once for every error that reaches the top of the chain. Errors has a complete JSON example, including mapping binding errors to 400.

type Validator interface {
Validate(any) error
}

Runs after every successful bind. An adapter for go-playground/validator is three lines, shown in Binding.

type JSONCodec interface {
Encode(w io.Writer, v any, indent string) error
Decode(r io.Reader, v any) error
}

Used by c.JSON, c.JSONPretty, and JSON binding. Swap in a faster library, or tune encoding/json:

type strictJSON struct{}
func (strictJSON) Encode(w io.Writer, v any, indent string) error {
enc := json.NewEncoder(w)
enc.SetIndent("", indent)
return enc.Encode(v)
}
func (strictJSON) Decode(r io.Reader, v any) error {
dec := json.NewDecoder(r)
dec.DisallowUnknownFields() // reject fields the struct does not declare
return dec.Decode(v)
}
type Renderer interface {
Render(w io.Writer, name string, data any, c *zinc.Context) error
}

Zinc’s template renderers cover html/template, text/template, and any engine with an ExecuteTemplate method. See Templates.

type RequestBinder interface {
Bind(*zinc.Context, any) error
BindBody(*zinc.Context, any) error
BindQuery(*zinc.Context, any) error
BindForm(*zinc.Context, any) error
BindHeader(*zinc.Context, any) error
BindPath(*zinc.Context, any) error
}

Replacing the binder changes how every c.Bind() method decodes. Most apps never need this; a custom JSONCodec or Validator usually covers the requirement.

For listeners, TLS, and lifecycle, you do not need configuration at all. The app is an http.Handler:

server := &http.Server{Addr: ":8443", Handler: app, TLSConfig: tlsConfig}
log.Fatal(server.ListenAndServeTLS("", ""))

app.Serve(listener) runs the app on a listener you created, such as a systemd socket or a Unix socket.