Michael Noack
Michael Noack

Reputation: 356

How to strictly unmarshall a go fixed length array?

I have a coords coming back in JSON

Whilst the API should always return them correct as an array of size 2, how can we enforce the structure is correct and raise an error when unmarshaling (apart from a very manual process). See example case if json is invalid.

package main

import (
    "fmt"
    "encoding/json"
)

// ResultType
type Location struct {
    Coordinates [2]int `json:"coords,array[20]"`
}

func main() {
    fmt.Println("Hello, playground")

    result := Location{}
    jsonBodyTooManyCoords := `{"coords": [1, 2, 3]}`
    json.Unmarshal([]byte(jsonBodyTooManyCoords), &result)
    fmt.Println(result) // Prints {1, 2}

    result = Location{}
    jsonBodyTooManyCoords = `{"coords": [1]}`
    json.Unmarshal([]byte(jsonBodyTooManyCoords), &result)
    fmt.Println(result) // Prints {1, 0}
}

Upvotes: 0

Views: 699

Answers (2)

Jonathan Hall
Jonathan Hall

Reputation: 79526

This sort of enforcement requires a custom type and custom unmarshaler. You could do something like this:

type coord [2]int

func (c *coord) UnmarshalJSON(data []byte) error {
    var x []int
    if err := json.Unmarshal(data, &x); err != nil {
        return err
    }
    if len(x) > 2 {
        return errors.New("Too many values")
    }
    if len(x) < 2 {
        return errors.New("Too few values")
    }
    copy((*c)[:], x)
    return nil
}

Then use your custom type:

// ResultType
type Location struct {
    Coordinates coord `json:"coords,array[20]"`
}

Upvotes: 0

Volker
Volker

Reputation: 42433

[H]ow can we enforce the structure is correct and raise an error when unmarshaling [...]?

You cannot.

Excess elements are silently discarded and missing values are returned as a zero value (both facts are documented in the documentation of encoding/json).

Also note that there is no array modifier, so your struct tags json:"cords,array[20]" seem strange.

If you want/need to handle malformed JSON array: Unmarshal into a slice and check its length.

Upvotes: 1

Related Questions