Не могу десериализовать JSON в объект структуры на Golang
Отправляю запрос на api сервер для получения json и вывожу его как строку в консоль.
r, err := http.Get("http://localhost:5500/website/actors")
if err != nil {
fmt.Println(err)
}
defer r.Body.Close()
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(bodyBytes))
JSON приходит в таком виде.
{
"actors": [
{
"ID": 1,
"FName": "1Name",
"LName": "2Name"
},
{
"ID": 2,
"FName": "Test",
"LName": "Test"
},
{
"ID": 3,
"FName": "Test",
"LName": "Test"
},
{
"ID": 4,
"FName": "Test",
"LName": "Test"
}
]
}
Пытаюсь его десериализовать и вывести в консоль.
type Actor struct {
ID int `json:"ID,omitempty"`
FName string `json:"FName,omitempty"`
LName string `json:"LName,omitempty"`
}
func (ac *Actor) GetActors() []Actor {
var actors []Actor
r, err := http.Get("http://localhost:5500/website/actors")
if err != nil {
fmt.Println(err)
}
defer r.Body.Close()
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
json_err := json.Unmarshal(bodyBytes, &actors)
if json_err != nil {
fmt.Println(json_err)
}
fmt.Println(actors)
return actors
}
Но на выходе я получаю пустой массив []. И при проверке на ошибку, я получаю:
"json: cannot unmarshal object into Go value of type []model.Actor".
Как исправить данную проблему?
Ответы (2 шт):
проблема в том, что JSON отличается от желаемой структуры.
в JSON есть объект actors, и только внутри него лежат массив Actor. Тогда итоговая структура в golang должна быть в виде map[string][]Actor
var body = []byte(`{
"actors": [
{
"ID": 1,
"FName": "1Name",
"LName": "2Name"
},
{
"ID": 2,
"FName": "Test",
"LName": "Test"
},
{
"ID": 3,
"FName": "Test",
"LName": "Test"
},
{
"ID": 4,
"FName": "Test",
"LName": "Test"
}
]
}`)
type Actor struct {
ID int `json:"ID,omitempty"`
FName string `json:"FName,omitempty"`
LName string `json:"LName,omitempty"`
}
func main() {
var data map[string][]Actor
json_err := json.Unmarshal(body, &data)
if json_err != nil {
fmt.Println(json_err)
}
fmt.Println(data)
for jsonObject, actors := range data {
fmt.Println(fmt.Sprintf("the data for object [%s] is %v", jsonObject, actors))
}
}
вывод
the data for object [actors] is [{1 1Name 2Name} {2 Test Test} {3 Test Test} {4 Test Test}]
Если вам важны только десериализаия и вывод, и не важна дальнейшая логика работы с данными, то абсолютно любой корректный json вы можете десериализовать в тип interface{} и вывести его на консоль.
Если же в дальнейшем с данными придется как то работать, то изучите API вашего ресурса и опишите соответствующие ему структуры.
У вас уже есть хоршо описанный тип Actor:
type Actor struct {
ID int `json:"ID,omitempty"`
FName string `json:"FName,omitempty"`
LName string `json:"LName,omitempty"`
}
Зачем API вашего ресурса устроен так, что по эндпоинту /website/actors возвращает список имеющий название, и кроме него ничего - понять сложно. Возможно в будущем туда добавятся еще какие-то поля или есть какая-то другая причина. Приведенный json соответствует примерно такому типу:
type Actors struct {
List []Actor `json:"actors"`
// сюда можно добавить другие поля
}
С примером довольно простого и понятного API сервиса с фильмами можно ознакомится здесь. Видно, что все списки возвращаются в чистом виде и могут быть десериализованы именно так, как вы делали в самом начале.