jsonutils icon indicating copy to clipboard operation
jsonutils copied to clipboard

`panic: json: cannot unmarshal string into Go value of type []string`

Open thenickcox opened this issue 10 years ago • 0 comments

I ran jsonutils on what the New York Times top stories API, and it spit out what looked like the correct format. But I'm getting panic: json: cannot unmarshal string into Go value of type []string when I run my code. Is this user error?

For reference, here's a sample API response:

{
  "status": "OK",
  "copyright": "Copyright (c) 2015 The New York Times Company. All Rights Reserved.",
  "section": "politics",
  "last_updated": "2015-12-27T14:40:04-05:00",
  "num_results": 26,
  "results": [
    {
      "section": "N.Y. / Region",
      "subsection": "",
      "title": "Christie Spins His Version of Security Record on Trail",
      "abstract": "An examination of Gov. Chris Christie’s record as New Jersey’s top federal prosecutor shows that he has, at times, overstated the significance of the terrorism prosecutions he oversaw.",
      "url": "http://www.nytimes.com/2015/12/27/nyregion/Christie-markets-himself-as-protector-to-gain-in-polls.html",
      "byline": "By ALEXANDER BURNS and CHARLIE SAVAGE",
      "item_type": "Article",
      "updated_date": "2015-12-26T18:04:19-5:00",
      "created_date": "2015-12-26T12:13:30-5:00",
      "published_date": "2015-12-27T00:00:00-5:00",
      "material_type_facet": "News",
      "kicker": "",
      "des_facet": [
        "Presidential Election of 2016",
        "Terrorism"
      ],
      "org_facet": [
        "Republican Party"
      ],
      "per_facet": [
        "Christie, Christopher J"
      ],
      "geo_facet": [
        "New Jersey"
      ],
      "multimedia": [
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-thumbStandard.jpg",
          "format": "Standard Thumbnail",
          "height": 75,
          "width": 75,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        },
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-thumbLarge.jpg",
          "format": "thumbLarge",
          "height": 150,
          "width": 150,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        },
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-articleInline.jpg",
          "format": "Normal",
          "height": 126,
          "width": 190,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        },
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-mediumThreeByTwo210.jpg",
          "format": "mediumThreeByTwo210",
          "height": 140,
          "width": 210,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        },
        {
          "url": "http://static01.nyt.com/images/2015/12/27/nyregion/27CHRISTIE1/27CHRISTIE1-superJumbo.jpg",
          "format": "superJumbo",
          "height": 1363,
          "width": 2048,
          "type": "image",
          "subtype": "photo",
          "caption": "Gov. Chris Christie of New Jersey spoke about the Sept. 11, 2001, attacks at a Republican conference last month.",
          "copyright": "Stephen Crowley/The New York Times"
        }
      ]
    }
]

Accordingly, jsonutils gave this structure:

type PoliticsJson struct {
    Copyright   string    `json:"copyright"`
    LastUpdated time.Time `json:"last_updated"`
    NumResults  int64     `json:"num_results"`
    Results     []struct {
        Abstract          string   `json:"abstract"`
        Byline            string   `json:"byline"`
        CreatedDate       string   `json:"created_date"`
        DesFacet          []string `json:"des_facet"`
        GeoFacet          []string `json:"geo_facet"`
        ItemType          string   `json:"item_type"`
        Kicker            string   `json:"kicker"`
        MaterialTypeFacet string   `json:"material_type_facet"`
        Multimedia        []struct {
            Caption   string `json:"caption"`
            Copyright string `json:"copyright"`
            Format    string `json:"format"`
            Height    int64  `json:"height"`
            Subtype   string `json:"subtype"`
            Type      string `json:"type"`
            URL       string `json:"url"`
            Width     int64  `json:"width"`
        } `json:"multimedia"`
        OrgFacet      []string `json:"org_facet"`
        PerFacet      []string `json:"per_facet"`
        PublishedDate string   `json:"published_date"`
        Section       string   `json:"section"`
        Subsection    string   `json:"subsection"`
        Title         string   `json:"title"`
        UpdatedDate   string   `json:"updated_date"`
        URL           string   `json:"url"`
    } `json:"results"`
    Section string `json:"section"`
    Status  string `json:"status"`
}

That looks right.

My go code is pretty simple:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

type PoliticsJson struct {
    Copyright   string    `json:"copyright"`
    LastUpdated time.Time `json:"last_updated"`
    NumResults  int64     `json:"num_results"`
    Results     []struct {
        Abstract          string   `json:"abstract"`
        Byline            string   `json:"byline"`
        CreatedDate       string   `json:"created_date"`
        DesFacet          []string `json:"des_facet"`
        GeoFacet          []string `json:"geo_facet"`
        ItemType          string   `json:"item_type"`
        Kicker            string   `json:"kicker"`
        MaterialTypeFacet string   `json:"material_type_facet"`
        Multimedia        []struct {
            Caption   string `json:"caption"`
            Copyright string `json:"copyright"`
            Format    string `json:"format"`
            Height    int64  `json:"height"`
            Subtype   string `json:"subtype"`
            Type      string `json:"type"`
            URL       string `json:"url"`
            Width     int64  `json:"width"`
        } `json:"multimedia"`
        OrgFacet      []string `json:"org_facet"`
        PerFacet      []string `json:"per_facet"`
        PublishedDate string   `json:"published_date"`
        Section       string   `json:"section"`
        Subsection    string   `json:"subsection"`
        Title         string   `json:"title"`
        UpdatedDate   string   `json:"updated_date"`
        URL           string   `json:"url"`
    } `json:"results"`
    Section string `json:"section"`
    Status  string `json:"status"`
}

func retrieveData() []byte {
    url := "http://api.nytimes.com/svc/topstories/v1/politics.json?api-key=MYAPIKEY"
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    return body
}

func main() {
    var p PoliticsJson

    err := json.Unmarshal(retrieveData(), &p)
    if err != nil {
        panic(err)
    }
    fmt.Println(p)
}

Edit

It seems to be the []strings this is having trouble with. Removing all of them but Multimedia, I get

panic: json: cannot unmarshal string into Go value of type []struct { Caption string "json:\"caption\""; Copyright string "json:\"copyright\""; Format string "json:\"format\""; Height int64 "json:\"height\""; Subtype string "json:\"subtype\""; Type string "json:\"type\""; URL string "json:\"url\""; Width int64 "json:\"width\"" }

It apparently doesn't like unmarshaling the mutlimedia key into an array of multimedia structs for some reason…?

Removing all of the fields for multimedia except URL gives this:

panic: json: cannot unmarshal string into Go value of type []struct { URL string "json:\"url\"" }

And removing the multimedia struct slice entirely gives the expected parsed JSON result. So it seems like it's treating the multimedia JSON array as a string…?

But changing it to

Multimedia string `json:"multimedia"`

Gives the error panic: json: cannot unmarshal array into Go value of type string, which suggests it _is_treating it as an array.

thenickcox avatar Dec 28 '15 06:12 thenickcox