Golang for json to allow value not necessarily to be an array

I am trying to change the policy for the s3 bucket to aws. I created the following json structure for the policy:

type Policy struct {
    Version     string  `json:"Version"`
    Id          string  `json:"Id"`
    Statement   []Statement `json:"Statement"`
}

type Statement struct {
    Sid         string      `json:"Sid"`
    Effect      string      `json:"Effect"`
    Principal   Principal   `json:"Principal"`
    Action      []string    `json:"Action"`
    Resource    []string    `json:"Resource"`
}

type Principal struct {
    AWS[]string `json:"AWS"`
}

Which is great for posting bucket rules. The problem occurs when I try to get the current policy and change it.

If there is an operator that has only one AWS, Action, or Resource value, Amazon will convert it from the array to a simple value, resulting in my unmarshalling will fail.

Is there any way to specify AWS / Action / Resource values ​​as a slice of a string or just a string?


I know that there are packages that I could use to get around this to some extent ( github.com/Jeffail/gabsfor example), but it would be easier to just create a JSON structure, as it is quite simple.

+4
2

interface{} MaybeSlice MarshalJSON UnmarshalJSON.

type MaybeSlice []string

func (ms *MaybeSlice) MarshalJSON() ([]byte, error) {
    // Use normal json.Marshal for subtypes
    if len(*ms) == 1 {
        return json.Marshal(([]string)(*ms)[0])
    }
    return json.Marshal(*ms)
}

func (ms *MaybeSlice) UnmarshalJSON(data []byte) error {
    // Use normal json.Unmarshal for subtypes
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        var v []string
        if err := json.Unmarshal(data, &v); err != nil {
             return err
        }
        *ms = v
        return nil
    }
    *ms = []string{s}
    return nil
}

, MaybeSlice , json.Marshal json.Unmarshal, , .

MaybeSlice - , , , .

struct, , . , Action a *MaybeSlice, .

+2

interface{}, , , :

type Statement struct {
    Sid       string    `json:"Sid"`
    Effect    string    `json:"Effect"`
    Principal Principal `json:"Principal"`

    Action   interface{} `json:"Action"`
    Resource interface{} `json:"Resource"`
}

:

//Example: Trying to access Action member of a statement myStatement.
switch a := myStatement.Action.(type) {
    case []string:
        //Action is a slice. Handle it accordingly.
    case string:
        //Action is a string. Handle it accordingly.
    default:
        //Some other datatype that can be returned by aws?
}

, Unmarshaling one failed, Unmarshal , - :

err := json.Unmarshal(jsonStr, &struct1)
if err != nil {
    fmt.Println(err)
    err = json.Unmarshal(jsonStr, &struct2)
}
+1

Source: https://habr.com/ru/post/1650063/


All Articles