Hello,
Feeling a little dumb here. I have been trying to punMarshal an API response in json to a struct. All the examples I can find that show text examples are in the proper format for unmarshaling with []byte('{json}')
Here is an example of one that works: https://play.golang.org/p/PjMR47dbzgu
When I add the surrounding brackets to match my return, like in this example: https://play.golang.org/p/HE16jtwyKFE , So the text example is surrounded like this: []byte('[{json}]'
I get the following error: "json: cannot unmarshal array into Go value of type main.Example"
I keep getting stuck in a circle changing things around to match different examples I keep finding, but I can't find one that has the brackets around the outside and works.
Any tips? Thanks
评论:
shovelpost:
anossov:Also when it doubt you can use a site like https://mholt.github.io/json-to-go/ to generate a struct that is right for your JSON.
For example
[ { "type":"example", "data":{ "name":"abc", "labels":{ "key":"value" } }, "subsets":[ { "addresses":[ { "ip":"192.168.103.178" } ], "ports":[ { "port":80 } ] } ] } ]
turns to
type AutoGenerated []struct { Type string `json:"type"` Data struct { Name string `json:"name"` Labels struct { Key string `json:"key"` } `json:"labels"` } `json:"data"` Subsets []struct { Addresses []struct { IP string `json:"ip"` } `json:"addresses"` Ports []struct { Port int `json:"port"` } `json:"ports"` } `json:"subsets"` }
You can then take that and split it so that it is clean in your code.
vapehound:That's a list of things, you have to unmarshal into a slice: https://play.golang.org/p/watM21z9eiZ
pharrisee:Thanks!
fourgbram:This can also be handy for building the boilerplate and then you simply customise (assuming you're using VSCode here of course):
https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype
vapehound:I had the same problem a couple of days ago and I think I solved it. Basically when you make a json.Decoder, you have to call
decoder.Token
before callingdecoder.Decode
Experience gophers please let me know if this is correct or not.
meowtasticly:Thanks, /u/anssov ‘s solution worked for me.
jerf:I've worked with a fair amount of JSON in Go and never knew decoder.Token existed... So no, I don't think that's correct for simple parsing like OP is working on.
It isn't necessarily wrong or right, it depends on what you are trying to do.
decoder.Token
will yield the first token in the stream, which in this case is the opening of a list. Then anything else you try to consume will be as if that token wasn't there. If you have a list that you know has one element in it, which is what you really want to decode, then that is a fine solution in the real world of ugly JSON. However, bear in mind that with that approach you won't get any observable difference between[{}]
(a list of one object) and[{}, {}]
(a list of two objects); in both cases you'll skip the list open and decode the first object, and there will be no errors. In general after decoding the first object I'd call .Token again and verify that it is a closed list as I expect, and at least log a warning if it isn't what I expected. I would also verify that the first token is the opening of a list before proceding and failing out if it is not.This technique has other uses as well. If you have a very long JSON document that is a list of smaller objects (just a lot of them), you can use this technique to pop off the list delimiter, then start iterating through the objects one at a time, instead of parsing the entire JSON file in one shot and marshaling all of the objects into RAM at once. Very useful stuff, in the right circumstances.
