gpt4 book ai didi

json - 如何解析包装的json对象

转载 作者:IT王子 更新时间:2023-10-29 02:01:05 27 4
gpt4 key购买 nike

某些 API 端点可能返回成功结果或错误,如下所示:

// ok
{
"status": "ok",
"payload": {
"id": 10,
"title": "Sample"
},
"request_id": "lx-VHr4OLm"
}
// error
{
"status": "error",
"payload": {
"message": "internal error"
},
"trace_id": "lx-VHr4OLm"
}

我正在尝试寻找一种优雅的方式来使用 Go 进行解析,就像这样

.... some code
if status == "ok" {
struct := AppStruct{} // AppStruct contains 2 fields: id and title
_ := json.Unmarshall(payloadBody, &struct)
return struct
} else {
errorStruct := ErrorStruct{} // contains 1 field for message.
_ := json.Unmarshall(payloadBody, &errorStruct)
return nil, errors.New(errorStruct.Message)
}

我当前的代码不适用于成功负载:

var result map[string]interface{}
jsonErr := json.Unmarshal(body, &result)
if jsonErr != nil {
return nil, jsonErr
}
if result["status"] == "error" {
errorPayload := result["payload"].(map[string]string)
return nil, errors.New(errorPayload["message"])
} else if result["status"] == "ok" {
apiResponse := AppInfo{}
jsonErr := json.Unmarshal([]byte(result["payload"].(string)), &apiResponse)
if jsonErr != nil {
return nil, jsonErr
}
return &apiResponse, nil
}

我在行 json.Unmarshal([]byte(result["payload"].(string)), &apiResponse)

上遇到了运行时错误

http: panic serving [::1]:51091: interface conversion: interface {} is map[string]interface {}, not string

当然,我可能有 2 个结构:成功响应和错误响应,但我认为解决我的问题的方法太复杂了。

如何以优雅的方式解析这个 JSON?

最佳答案

我真的不确定是什么问题。标准 encoding/json 不要求结构匹配 JSON 数据中的所有 字段。使用一个简单的类型来处理这个问题非常容易:

type Payload struct {
ID int `json:"id"`
Title string `json:"title"`
Message string `json:"message"`
}

type Response struct {
Status string `json:"status"`
ID string `json:"request_id"`
TraceID string `json:"trace_id"`
Payload Payload `json:"payload"`
}

然后在 Response 结构中解码响应:

var resp Response
if err := json.Unmarshal(body, &resp); err != nil {
return err
}

然后您可以简单地检查Status 字段,并确定下一步要做什么。例如:

if resp.Status == "error" {
return fmt.Errorf("invalid response: %s - %s", resp.TraceID, resp.Payload.Message)
}
// handle resp.Payload.ID and resp.Payload.Title fields
return nil

您可以根据复杂性和您的特定需求,将状态字段的这些检查移动到响应对象上的接收函数。

也许值得为那些未在正常响应中设置的字段使用指针字段,并使用 omitempty 选项标记它们:

type Payload struct {
ID int `json:"id"`
Title string `json:"title"`
Message *string `json:"message,omitempty"`
}
type Response struct {
Status string `json:"status"`
ID string `json:"request_id"`
TraceID *string `json:"trace_id,omitempty"`
Payload Payload `json:"payload"`
}

有了这样的类型,不再需要依赖硬编码的字符串常量来检查错误。相反,您可以像这样轻松实现更通用的检查:

func (r Response) IsError() bool {
return (r.TraceID == nil) // will be set in case of an error response
}

更新

正如您在评论中指出的那样,响应主体实际上比示例中的 2 个字段大得多。当然,复制粘贴结构定义,或编写映射函数以将 Payload 映射到您已有的类型上是没有意义的。

这里的答案是:组合。

type Payload struct {
AppStruct // embedded the AppStruct type
Message *string `json:"message"`
}

Response 类型保持原样。如果响应成功,您可以直接从响应中获取 AppStruct,如下所示:

appStruct := resp.Payload.AppStruct

这是有效的,因为类型是嵌入的。请注意,那里没有任何 json 标记。至少就解码而言,嵌入式结构是 Payload 结构的一部分。因此,该类型的所有导出字段将直接解码到结构中。

关于json - 如何解析包装的json对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54025961/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com