Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
input validation sanely
package main
import (
"encoding/json"
"errors"
"net/http"
"github.com/asaskevich/govalidator"
)
// main - a simple main entry point
func main() {
srv := &http.Server{
Addr: ":1234",
Handler: f,
}
srv.ListenAndServe()
}
// f - our only application handler to demonstrate validation
var f http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
// we have an input structure, of type Thing
var thing *Thing
// we want to decode and validate Thing from request body
err := decodeAndValidate(r, thing)
// there was an error with Thing
if err != nil {
// send a bad request back to the caller
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("bad request"))
return
}
// it was decoded, and validated properly, success
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
// decodeAndValidate - entrypoint for deserialization and validation
// of the submission input
func decodeAndValidate(r *http.Request, v InputValidation) error {
// json decode the payload - obviously this could be abstracted
// to handle many content types
if err := json.NewDecoder(r.Body).Decode(v); err != nil {
return err
}
defer r.Body.Close()
// peform validation on the InputValidation implementation
return v.Validate(r)
}
// InputValidation - an interface for all "input submission" structs used for
// deserialization. We pass in the request so that we can potentially get the
// context by the request from our context manager (future net.http will include
// a context in the request)
type InputValidation interface {
Validate(r *http.Request) error
}
var (
// ErrInvalidUUID - error when we have a UUID validation issue
ErrInvalidUUID = errors.New("invalid uuid")
// ErrInvalidName - error when we have an invalid name
ErrInvalidName = errors.New("invalid name")
)
// Thing - is our implemenation of InputValidation and the structure we will
// deserialize into
type Thing struct {
ID string `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
}
// Validate - implementation of the InputValidation interface
func (t Thing) Validate(r *http.Request) error {
// validate the ID is a uuid
if !govalidator.IsUUID(t.ID) {
return ErrInvalidUUID
}
// validate the name is not empty or missing
if govalidator.IsNull(t.Name) {
return ErrInvalidName
}
return nil
}
@sengkathir

This comment has been minimized.

Copy link

@sengkathir sengkathir commented Apr 2, 2017

json.NewDecoder(r.Body).Decode(v) returns error for valid input.

@jian-en

This comment has been minimized.

Copy link

@jian-en jian-en commented Nov 28, 2017

line 23: should be -> var thing Thing

@jian-en

This comment has been minimized.

Copy link

@jian-en jian-en commented Nov 28, 2017

line 25: should be -> err := decodeAndValidate(r, &thing)

@elsonwu

This comment has been minimized.

Copy link

@elsonwu elsonwu commented Feb 28, 2018

How to validate the value is posted from client or the default value from go itself?

For example if you have a bool field, IsOnSold

type Thing struct {
ID string json:"id"
Name string json:"name"
Category string json:"category"
IsOnSold bool json:"is_on_sold"
}

If the client only POST id, name, and category, but without this is_on_sold, and it has a default false value, so you thought it POST it, then it might cause issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.