mrasoolmirza
mrasoolmirza

Reputation: 897

How to handle null values in json response in Go using json.NewDecoder

This is my struct:

type Media struct {
    MediaID   string `json:"media_id"`
    MediaType float64    `json:"media_type"`
    ViewCount float64    `json:"view_count"`
}

I'm writing an API to serve some media files and I'm using json.NewDecoder to decode and work with the response. I populate my struct like this way:

media := Media{
                MediaID:   media["media_id"].(string),
                MediaType: media["media_type"].(float64),
                ViewCount: media["view_count"].(float64),
}

It works fine in many situations but the problem is that sometimes view_count is null and it gives me this error:

interface conversion: interface {} is nil, not float64

I really appreciate any comments!

This is all the code before trying to extract response fields:

var (
    r  map[string]interface{}
)

var buf bytes.Buffer

query := map[string]interface{}{
    "query": map[string]interface{}{
        "match": map[string]interface{}{
            "content": params["q"],
        },
    },
}

if err := json.NewEncoder(&buf).Encode(query); err != nil {
    log.Fatalf("Error encoding query: %s", err)
}

res, err = es.Search(
    es.Search.WithContext(context.Background()),
    es.Search.WithIndex("myindex"),
    es.Search.WithBody(&buf),
    es.Search.WithTrackTotalHits(true),
    es.Search.WithPretty(),
)

if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
    log.Fatalf("Error parsing the response body: %s", err)
}

Upvotes: 3

Views: 1939

Answers (2)

RelectoDetecto
RelectoDetecto

Reputation: 11

The numeric fields in Media should probably be integer values instead of floating point values:

type Media struct {
    MediaID   string `json:"media_id"`
    MediaType int    `json:"media_type"`
    ViewCount int    `json:"view_count"`
}

Use pointers if the numeric fields if the JSON document uses null for these values. Hopefully that's not the case because the application must write a bit of extra code to deference the pointers.

type Media struct {
    MediaID   string `json:"media_id"`
    MediaType *int    `json:"media_type"`
    ViewCount *int    `json:"view_count"`
}

Either way, decode directly to Media as suggested in the question's commentary:

var media Media
if err := json.NewDecoder(res.Body).Decode(&media); err != nil {
    log.Fatalf("Error parsing the response body: %s", err)
}

Upvotes: 1

Diako Sharifi
Diako Sharifi

Reputation: 463

If you have nil for some fields, solution is POINTER!

this code is enough if you use binding

type Media struct {
    MediaID   string `json:"media_id"`
    MediaType float64    `json:"media_type"`
    ViewCount *float64    `json:"view_count"`
}

but if you wanna assign it field by field (which is not a good idea) before assigning you should check if media["view_count"] is exist or not

var viewCount float64
tmpViewCount, ok := madia["view_count"]
if ok {
   viewCount = tmpViewCount.(float64)
}

media := Media{
   MediaID:   media["media_id"].(string),
   MediaType: media["media_type"].(float64),
   ViewCount: viewCount,
}

Upvotes: 2

Related Questions