猿问

惯用的 JSON 对象数组 -> map[string]json.RawMessage

我正在尝试解组 HTTP REST API 请求的结果,该请求根据结果的数量返回一个对象或一个对象数组。


请求是通用的,因为我试图围绕特定的 REST API 构建一个包装器,它被称为:


// Function prototype where I am trying to convert the response

func (client *Client) Get(endpoint string, data map[string]string) (map[string]json.RawMessage, error)


// The way the function is called

client.Get("/v1/users", map[string]string{"filter.abc": "lorem ipsum"})

两个响应示例:


[

  {

    "abc": "def",

    "efg": 123

    "hij": [

      {

        "klm": "nop"

      }

    ]

  },

  {

    "abc": "def",

    "efg": 123

    "hij": [

      {

        "klm": "nop"

      }

    ]

  }

]

// RESPONSE 1: Array of JSON objects that have child arrays


{

  "abc": "def",

  "efg": 123

  "hij": [

    {

      "klm": "nop"

    }

  ]

}

// RESPONSE 2: In this case, only one element was returned.

我已经实现了仅针对响应 2 执行此操作,如下所示:


// [...]

byteBody = ioutil.ReadAll(res.Body)

// [...]

var body map[string]json.RawMessage

if err := json.Unmarshal(byteBody, &body); err != nil { [...] }

那么,最惯用的解析方式是什么?有没有办法避免编写冗余代码并解析两个响应?我正在考虑将响应放入的“模型”作为附加参数。这是一个好习惯吗?非常感谢您!


不负相思意
浏览 135回答 2
2回答

湖上湖

检查 JSON 文档中的第一个非空白字节以确定文档是数组还是对象。func decodeArrayOrObject(doc []byte) ([]map[string]json.RawMessage, error) {    trimmedDoc := bytes.TrimSpace(doc)    switch {    case len(trimmedDoc) == 0:        return nil, errors.New("empty body")    case trimmedDoc[0] == '{':        var m map[string]json.RawMessage        err := json.Unmarshal(doc, &m)        return []map[string]json.RawMessage{m}, err    case trimmedDoc[0] == '[':        var s []map[string]json.RawMessage        err := json.Unmarshal(doc, &s)        return s, err    default:        return nil, errors.New("unexpected type")    }}使用reflect包创建一个适用于任意切片类型的函数:func decodeArrayOrObject(doc []byte, slicep interface{}) error {    trimmedDoc := bytes.TrimSpace(doc)    switch {    case len(trimmedDoc) == 0:        return errors.New("empty document")    case trimmedDoc[0] == '[':        return json.Unmarshal(doc, slicep)    case trimmedDoc[0] == '{':        s := reflect.ValueOf(slicep).Elem()        s.Set(reflect.MakeSlice(s.Type(), 1, 1))        return json.Unmarshal(doc, s.Index(0).Addr().Interface())    default:        return errors.New("unexpected type")    }}使用指向结构切片的指针或指向结构指针切片的指针调用函数。var v []Exampleerr := decodeArrayOrObject(body, &v)

呼唤远方

不确定是惯用的,但这段代码可以作为一个例子。简而言之,您可以尝试以一种格式解组,如果失败,则以另一种格式解组关键功能是func parseStr(data string) ([]Item, error) {    item := Item{}    if err := json.Unmarshal([]byte(data), &item); err == nil {        return []Item{item}, nil    }    items := []Item{}    if err := json.Unmarshal([]byte(data), &items); err != nil {        return nil, errors.New("invalid JSON data")    }    return items, nil}
随时随地看视频慕课网APP

相关分类

Go
我要回答