3 ms·
Thanks, that's neat! The challenge here is that I also need to validate values (e.g. support minimum/maximum), not just within structs, but also standalone valu
by atombender 8y ago
Thanks, that's neat! The challenge here is that I also need to validate values (e.g. support minimum/maximum), not just within structs, but also standalone values, which means an UnmarshalJSON directly on the type. I might end up doing something like your example, though. (Rejecting extra fields is on my list!)
- Vendan 8y agothe json.NewDecoder stuff does still trigger unmarshals of the types in the struct and such: i.e. package main import ( "bytes" "encoding/json" "errors" "fmt" ) func main() { fmt.Println("Hello, playground") var p Post err := json.Unmarshal([]byte(`{"title": "test"}`), &p) fmt.Println(err, p) err = json.Unmarshal([]byte(`{"title2": "test"}`), &p) fmt.Println(err, p) err = json.Unmarshal([]byte(`{}`), &p) fmt.Println(err, p) err = json.Unmarshal([]byte(`{"title": "long test"}`), &p) fmt.Println(err, p) } type Post struct { Title ShortTitle `json:"title"` } func (v *Post) UnmarshalJSON(b []byte) error { dec := json.NewDecoder(bytes.NewReader(b)) required := map[string]struct{}{ "title": struct{}{}, } tok, err := dec.Token() if err != nil { return err } if d, ok := tok.(json.Delim); !ok || d != '{' { return errors.New("Expected object") } for { tok, err := dec.Token() if err != nil { return err } if d, ok := tok.(json.Delim); ok && d == '}' { break } switch tok { case "title": delete(required, "title") err := dec.Decode(&v.Title) if err != nil { return err } default: (*v) = Post{} return errors.New(fmt.Sprintf("Unexpected field %s", tok)) } } if len(required) > 0 { (*v) = Post{} return errors.New(fmt.Sprintf("Missing %v required fields", len(required))) } return nil } type ShortTitle string func (st *ShortTitle) UnmarshalJSON(b []byte) error { var tmpst string err := json.Unmarshal(b, &tmpst) if err != nil { return err } if len(tmpst) > 6 { return errors.New("Title too long!") } *st = ShortTitle(tmpst) return nil }