Lately I’ve been working through the very arduous (for me) process of learning Go for some personal projects. I selected Go because I typically use interpretted, dynamically typed languages for work, so I thought it would be a good learning experience to work with a compiled, statically typed language. To me at least, Go seemed a bit more approachable than something like C or Rust. I started trying to learn Kotlin since I’ve been working with another JVM-based language in Groovy, but it’s extremely difficult to use Kotlin from just the command line without an IDE; when I couldn’t figure out how to add an external package to a project without an IDE I basically gave up on it since it didn’t fit at all into my workflow. Go, on the other hand, has a handy package manager built into the same binary you use to compile your own code.

After going through a book to get the basics of Go down (I won’t link the book because I actually thought it was a pretty terrible source, and I wouldn’t recommend it) I jumped in to doing a little bit of API work since that’ll be important for some of the project ideas I’m kicking around. It was fairly simple to look up how to leverage the io/ioutil and net/http packages to make an unauthenticated call to a REST API endpoint. This gives the data back in a byte slice. I can cast that to a string to view it and verify that I got back the expected data, but obviously I can’t actually do anything I want with the data in a byte slice. In many other languages this is where I would use some type of JSON library to parse the response into something like a map/hashtable/dictionary. I’m used to languages where the interpreter just kind of figures that out for you based on the syntax of the JSON.

Go isn’t like that, though. Instead, I need to define a struct that matches the format of the API response. If I have that, I can use the encoding/json package in Go to create a struct. That’s something I could do manually, but that would be extremely tedious. For example, this is what I see when dumping the byte array I get back from querying my own Mastodon account as a string:

"id":"49","username":"failtime","acct":"failtime","display_name":"failtime","locked":false,"bot":false,"discoverable":false,"group":false,"created_at":"2017-04-24T15:48:10.334Z","note":"\u003cp\u003eProfessional loser.\u003c/p\u003e","url":"https://mastodon.sdf.org/@failtime","avatar":"https://mastodon.sdf.org/system/accounts/avatars/000/000/049/original/3fe810f812b83712.jpg?1567388103","avatar_static":"https://mastodon.sdf.org/system/accounts/avatars/000/000/049/original/3fe810f812b83712.jpg?1567388103","header":"https://mastodon.sdf.org/system/accounts/headers/000/000/049/original/45632b66add48db3.jpg?1592224165","header_static":"https://mastodon.sdf.org/system/accounts/headers/000/000/049/original/45632b66add48db3.jpg?1592224165","followers_count":99,"following_count":69,"statuses_count":1880,"last_status_at":"2020-06-27","emojis":[],"fields":[{"name":"Blog","value":"\u003ca href=\"https://failti.me\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003efailti.me\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e","verified_at":"2020-06-24T00:27:59.294+00:00"},{"name":"Laifu","value":"\u003ca href=\"https://laifu.moe\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003elaifu.moe\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e","verified_at":"2020-06-15T00:37:19.734+00:00"}]}

I really don’t want to have to go through that to create a struct out of it. I started digging around to see if there was a better way and, as is usually the case when dealing with code, came across a Stack Overflow post on the topic. Along with some other helpful information that I used to improve my code a little, one of the replies linked to JSON-to-Go. The service allows me to paste in JSON output like what I included above in this post, and it will automatically generate the corresponding struct. I tried it out, and it nicely gave me the following:

type AutoGenerated struct {
    ID             string        `json:"id"`
    Username       string        `json:"username"`
    Acct           string        `json:"acct"`
    DisplayName    string        `json:"display_name"`
    Locked         bool          `json:"locked"`
    Bot            bool          `json:"bot"`
    Discoverable   bool          `json:"discoverable"`
    Group          bool          `json:"group"`
    CreatedAt      time.Time     `json:"created_at"`
    Note           string        `json:"note"`
    URL            string        `json:"url"`
    Avatar         string        `json:"avatar"`
    AvatarStatic   string        `json:"avatar_static"`
    Header         string        `json:"header"`
    HeaderStatic   string        `json:"header_static"`
    FollowersCount int           `json:"followers_count"`
    FollowingCount int           `json:"following_count"`
    StatusesCount  int           `json:"statuses_count"`
    LastStatusAt   string        `json:"last_status_at"`
    Emojis         []interface{} `json:"emojis"`
    Fields         []struct {
        Name       string    `json:"name"`
        Value      string    `json:"value"`
        VerifiedAt time.Time `json:"verified_at"`
    } `json:"fields"`
}

I pasted it into my code, changed the name from AutoGenerated to something a little more fitting, and sure enough I was now able to Unmarshal my API response into a usable struct… without having to go through the pain of creating the struct myself. Huge kudos to the creator for such an awesome and useful service.