Home Up Back Forward Leave Message


Overview

The code is available for download from:

JSON handling in Golang

For the marshaling and unmarshaling of JSON, golang already provide us with the capability to do that out of the box. We just need to provide it with the necessary structure or variable to do it for us. The package to use is "encoding/json" and the two main functions are json.Marshal and json.Unmarshal.
Let's take LogonStr which is the structure holding the logon data and this is how we will marshal it:

    type LogonStr struct {
	Username string `json:"username"`
	Password string `json:"password"`        
    }

    logon := LogonStr{"johnny","bravo"}
    buf, err := json.Marshal(logon)
The part after the field names that start with `json: indicates that for the JSON we want different fieldnames (in this case just the lower case). Golang expect the fieldnames in the struct to have and initial capital letter to be exportable else json.Marshal and json.Unmarshal cannot see them (they are essentially then private).

An instance of the struct is created with "johnny" as Username and "bravo" as Password and it is placed in logon.

json.Marshal is then called with logon and a json representation is created (if successful, which it should be in this case) and placed as a byte array in buf but if any error is experienced it is placed in err. To convert the byte array to string once can just call string(buf)

When a structure is only used once then we don't need to explicitly define it but we can make use of an anonymous structure, for example:
    logon := struct {
	Username string `json:"username"`
	Password string `json:"password"`        
    }{"johnny","bravo"}
    buf, err := json.Marshal(logon)
In this case the structure is only going to be used to generate json once. We can in fact do it all in one go:
    buf, err := json.Marshal(struct {
	Username string `json:"username"`
	Password string `json:"password"`        
    }{"johnny","bravo"})    


To unmarshal a byte array into above struct it is as easy as:
    logon := LogonStr{}
    err := json.Unmarshal(buf,&logon)
First an empty struct of the type that you want to unmarshal to is created (LogonStr in this case). Then the byte array (buf) and the empty struct is passed to json.Unmarshal. The data will be placed within their correct fields and if an error is experienced it will be returned.

When you don't want to have all fields unmarshalled (which can be the case that certain field need to be unmarshalled based on some logic) you can make that field json.Rawmessage. What this means is that json.Unmarshall will not try to figure out what type the field is and basicall just keep it as a byte array, which can then be unmarshalled further in code. For example:
    result := struct {
            Status bool            `json:"status"`
            Data   json.RawMessage `json:"data"`
    }{}
    err := json.Unmarshal(buf,&result)

    if err != nil {
        // Do some error handling
    } else {
        if result.Status {
            var sesskey int64
            err := json.Unmarshal(result.Data,&sesskey)
            // Do something with sesskey
        } else {
            var msg string
            err := json.Unmarshal(result.Data,&msg)
            // Do something with msg
        }
    }
Here we have a structure that is being returned and the status can be true (which indicates success and let's assume an int64 session key is returned then data) or false (which indicates failure and data has a string message for the error then).

Once again we create an empty structre instance, then we unmarshal to it. Only result.Status will be unmarshalled; result.Data will essentially just have the byte array representation of what is in data.

If no error has been returned we look at the result.Status if it is true we unmarshal it to an int64 (sesskey) else we unmarshal it to a string (msg). We've once again made use of an anonymous struct seeing that we are only using it within this code segment.

HTTP handling of calls

On the server side one has to include the following in all handling of calls:

	w.Header().Add("Access-Control-Allow-Origin", "*")
	w.Header().Add("Content-Type", "text/json;charset=UTF-8")    
This is to ensure tin the case a web browser communicates with the server it will allow cross domain AJAX calls.

Because we put the actual data transferred in the body of a POST call we need to get it in each case of the server handler function:
	buf, err := ioutil.ReadAll(r.Body)    
This is straight forward and just reads everything in the body and place it into buf (a byte array) or return an error. This byte array can then be passed straigth to a call of json.Unmarshal. The rest of the code should be relative self explanitory.