The Problem

I was working on implementing a new API endpoint in Go that renders a list of users in JSON. The idea is simple. Grab the users from DB, convert them into struct representation, marshall the array to JSON and return the JSON in the response body. Problem arises when I find out that one of the columns in the users table is a nullable varchar.

Before going to the Go implementation, I am going to digress a little. For those of you who are familiar with Rails, what I am trying to do is equivalent to the following:

User.all.to_json

The code above is very simple and quite magical. A lot of things are taken for granted here. Doing the same thing in Go is not as simple and requires a 2 step process: Convert the user entry from DB to structs and convert the structs to JSON string.

My users table definition looks like this in DB

id          `int`
first_name  `varchar(255)`
middle_name `varchar(255) DEFAULT NULL`
last_name   `varchar(255)`

And my struct definition for User looks like this in Go

type User struct {
   Id           uint32  `json:"id"`
   FirstName    string  `json:"first_name"`
   MiddleName   string  `json:"middle_name"`
   LastName     string  `json:"last_name"`
}

If you cannot see the problem already, think about what would happen if a user does not have a middle name (A NULL value in the database for middle_name attribute). This means that User instance would have a null value for its MiddleName field in Go-land. BEEEP! null for string field? Is that possible in Go-land? Nope.

Partial Solution

The database/sql package has a solution to this by providing a struct called NullString. sql.NullString has a boolean field called Valid that, when false, deems the value as null. Definition of NullString is as follows:

type NullString struct {
   String string
   Valid  bool // Valid is true if String is not NULL
}

So, to leverage this struct, I change the User definition to the following

type User struct {
   Id           uint32          `json:"id"`
   FirstName    string          `json:"first_name"`
   MiddleName   sql.NullString  `json:"middle_name"` //Changed
   LastName     string          `json:"last_name"`
}

Sweet! Now, conversion from DB-land to Go-land works! You can check if MiddleName is null by looking at the Valid field. If Valid is true, you can look at the value by accessing its String field. So far, so good and we are done with the first part (converting DB entry to Go struct).

Problem #2

Next, we want to be able to convert the user instance in Go-land to JSON string. Without doing anything else, if we try to convert (using json.Marshall) with the current struct definition, we are going to get something like this in JSON.

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : { "String" : "Ahoy?", "Valid" : true }, //JSON representation of sql.NullString
    "last_name" : "Suratna"
}

or, when middle_name is null in database

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : { "String" : "", "Valid" : false },
    "last_name" : "Suratna"
}

How did this happen? Well, take a look at how sql.NullString is defined and think how it would be represented in JSON. The middle_name field is marshalling the sql.NullString value to JSON. This is expected but not something that we want. What we really want is something like this:

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : "Ahoy?",
    "last_name" : "Suratna"
}

or, when middle_name is null in database

{
    "id" : 1,
    "first_name" : "Dennis",
    "middle_name" : null,
    "last_name" : "Suratna"
}

Solution using MarshalJSON

I tried a couple workarounds but I ended up implementing a custom MarshalJSON for the User struct. Here is the implementation:

func (u *User) MarshalJSON() ([]byte, error){
    middleNameValue, err := u.MiddleName.Value()

    if err != nil {
        return nil, err
    }

    var middleNameJsonString string

    if middleNameValue == nil {
        middleNameJsonString = "null"
    } else {
        middleNameJsonString = fmt.Sprintf("\"%s\"", titleValue)
    }

    jsonString := fmt.Sprintf("{\"id\":%d,\"first_name\":%s,\"middle_name\":%s,\"last_name\":%s}", u.Id, u.FirstName, middleNameJsonString, u.LastName)

    return []byte(jsonString), nil
}

I have to admit that this is not the cleanest solution (and probably not the best). However, it is a working one and it renders the JSON properly. If you have a better solution to this, please let me know!

Simple Slide Out Navigation Menu in iOS with Swift (Part 2)

Continuing from part 1, we are going to see how to switch the displayed view controller when one of the menu selections is tapped Continue reading

Subdomain with NGINX on Linode

Published on January 14, 2015