简体   繁体   English

在Go中解码变量模式JSON

[英]Decoding variable-schema JSON in Go

I'm asking this about Go's encoding/json , but I guess it also applies to any other JSON libraries that map JSON blobs to objects in whatever language. 我问这个关于Go的encoding/json ,但我想它也适用于将JSON blob映射到任何语言的对象的任何其他JSON库。

Here's an example. 这是一个例子。 If you want to a shorten a URL using the goo.gl URL shortener API , you get back either a successful response: 如果您想使用goo.gl URL缩短程序API缩短URL ,则可以获得成功的响应:

{
 "kind": "urlshortener#url",
 "id": "http://goo.gl/fbsS",
 "longUrl": "http://www.google.com/"
}

Or an error response: 或错误响应:

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Required",
    "locationType": "parameter",
    "location": "resource.longUrl"
   }
  ],
  "code": 400,
  "message": "Required"
 }
}

Is there an idiomatic way of dealing with this -- a response that could adhere to two completely different schemas? 有没有一种惯用的处理方式 - 一种可以遵循两种完全不同的模式的响应?

Normally I deal with JSON using maps/lists; 通常我使用地图/列表来处理JSON; I know that's possible in Go. 我知道Go中有可能。 I could unmarshal to a map[string]interface{} and then check if the map has "error" as a key. 我可以解组map[string]interface{} ,然后检查地图是否有"error"作为键。 But then I'd have to decode again into a proper struct , I think. 但是我认为我必须再次解码成一个合适的struct (Am I wrong?) (我错了吗?)

I'm doing something like this. 我正在做这样的事情。 I have one type for each kind of response: 我对每种响应都有一种类型:

type successResponse struct {
    Kind string
    Id string
    LongUrl string
}

type errorResponse struct {
    Error struct {
        Errors []struct {
            Domain string
            Reason string
            Message string
            LocationType string
            Location string
        }
        Code int
        Message string
    }
}

And decoding looks like this: 解码看起来像这样:

s := new(successResponse)
err := json.Unmarshal(blob, s)
if err == nil {
    // handle success
} else {
    e := new(errorResponse)
    err = json.Unmarshal(blob, e)
    if err == nil {
        // handle error response
    } else {
        // handle actual error
    }
}

But that seems kind of ugly. 但这看起来有点难看。 How should I approach this? 我该怎么做呢?

Since the fields in your json responses are distinct from each other you can just create one struct with the union of all the fields. 由于json响应中的字段彼此不同,因此您可以使用所有字段的并集创建一个结构。 The json decoder will ignore fields that are not present in the json string and you can test the existence of the fields to know which type of response you are getting back. json解码器将忽略json字符串中不存在的字段,您可以测试字段的存在以了解您要返回的响应类型。

I was confused about this, too, and thought I had to decode it again. 我也对此感到困惑,并认为我必须再次解码它。 You don't, though. 但是,你没有。 You just have to typecast the interface{} data into the appropriate structure. 您只需将接口{}数据类型转换为适当的结构即可。

For example if the json package has put the value into a generic interface{} , you can typecast it into ErrorType with error := val.(ErrorType) . 例如,如果json包已将值放入通用interface{} ,则可以将其类型转换为ErrorTypeerror := val.(ErrorType)

You can use foo.(type) in a switch statement to "do the right thing", if you are parsing based on what type the value is. 如果要根据值的类型进行解析,可以在switch语句中使用foo.(type)来“做正确的事”。

I've only been learning Go this week so it's not the prettiest code, but there are some examples in the geodns JSON configuration parsing . 我本周才学习Go,所以它不是最漂亮的代码,但是在geodns JSON配置解析中有一些例子。

Have you tried Go-SimpleJSON ? 你试过Go-SimpleJSON吗? I think this might solve your issue. 我认为这可能会解决您的问题。

type Response struct {
    Kind    string
    Id      string
    LongUrl string
    Error   struct {
        Errors []struct {
            Domain       string
            Reason       string
            Message      string
            LocationType string
            Location     string
        }
        Code    int
        Message string
    }
}

s := Response{}
if err := json.Unmarshal(blob, &s); err == nil {
    if s.Error == nil {
        // success
    } else {
        // error
    }
} else {
    // something went wrong
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM