DEV Community

Rodion Gorkovenko
Rodion Gorkovenko

Posted on

Go vs PHP, JSON and Earthquakes - part 2

So here is the web-service providing JSON data about earthquakes for the last day.

And in the previous post we tried rewriting Go code in PHP to fetch this JSON and print places and magnitudes of earthquakes.

Now we want the same with Go - parse JSON without explicit structs

I found it is not hard, but honestly I'm not quite happy with result. Perhaps you'll be able to hint further improvements.

Before going to details - here are full sources at github PHP Source and Go Source.

Now to details

First part - creating URL and loading JSON are similar to those in original post (by @cskonopka ) - let's skip it (the full code is in github by link above).

We come to point when we have body with json data as string. We can Unmarshall data to base type interface{} and then cast everything to suitable type dynamically:

    var data interface{}
    json.Unmarshal(body, &data)

    features := data.(map[string]interface{})["features"]
    for _, feature := range features.([]interface{}) {
        propsObj := feature.(map[string]interface{})["properties"]
        props := propsObj.(map[string]interface{})
        fmt.Println(props["place"], props["mag"])
    }

This works, but doesn't look very sexy. Obviously we can hide the typecasts to dedicated functions. Let's call them obj (returns map for json object) and arr (returns array for json list):

func obj(val interface{}) (map[string]interface{}) {
    return val.(map[string]interface{})
}

func arr(val interface{}) ([]interface{}) {
    return val.([]interface{})
}

and now we can rewrite our loop laconically:

    for _, feature := range arr(obj(data)["features"]) {
        props := obj(obj(feature)["properties"])
        fmt.Println(props["place"], props["mag"])
    }

It works all right. We can create general functions also to retrieve int, string etc.

Why I'm not very pleased is that I'd prefer to have object-oriented style here, e.g.

    // instead of
    range arr(obj(data)["features"])

    // I'd like
    range data.obj()["features"].arr()

this would be better for readability. Regretfully Unmarshall won't create
custom "general" type for me (instead of
interface{}`).

Perhaps there is a way to amend unmarshaller's behavior. I'll study this. If you know - please hint!

Top comments (0)