To Unmarshal() or To Decode() for JSON?
If you are like me and want to learn backend development, you probably came across JSON handling at one point. JSON is a very popular format for transferring data between the front and backend. Because it is such an essential feature in modern web development, Golang adds support for JSON in its encoding/json
package.
The problem is that there isn’t only one way of doing things. If you have watched a couple of tutorials in the past, you may have noticed people using different functions to handle JSON. Some people use Marshal
and Unmarshal
, while others use Encode
and Decode
. What should you use? Which one is better? In this blog post, I will explain the difference between the two approaches and when you should use one over the other. Enjoy!
Two approaches for JSON processing with Golang
There are two ways to read and write JSON. This code snippet will help you understand how to use the two approaches. First, Marshal
and Unmarshal
:
func PrettyPrint(v interface{}) (err error) {
b, err := json.MarshalIndent(v, "", "\t")
if err == nil {
fmt.Println(string(b))
}
return err
}func TryMarshal() error {
data := map[string]interface{}{
"1": "one",
"2": "two",
"3": "three",
}
result, err := json.Marshal(&data)
if err != nil {
return err
} err = PrettyPrint(result)
if err != nil {
return err
} return nil
}func TryUnmarshal() error {
myFile, err := os.Open("test.csv")
if err != nil {
return err
}
defer myFile.Close() data, err := io.ReadAll(myFile)
if err != nil {
return err
} var result map[string]interface{}
json.Unmarshal([]byte(data), &result) err = PrettyPrint(result)
if err != nil {
return err
} return nil
}
In TryMarshal
, I created a map[string]interface{}
to hold some data. I then passed it to Marshal
.
In TryUnmarshal
, I read a file and converted it into a byte slice data
. That data
is passed into Unmarshal
, which stores the result in a map[string]interface{}
.
PrettyPrint
just formats the output to make it look nice.
Now let’s take a look at Encoder.Encode
and Decoder.Decode
.
func TryEncode() error {
data := map[string]interface{}{
"1": "one",
"2": "two",
"3": "three",
}
err := json.NewEncoder(os.Stdout).Encode(&data)
if err != nil {
return err
} return nil
}func TryDecode(path string) error {
myFile, err := os.Open(path)
if err != nil {
return err
}
defer myFile.Close() var result map[string]interface{}
json.NewDecoder(myFile).Decode(&result) return nil
}
The code looks pretty similar to the previous example. TryEncode
is analogous to TryMarhsal
and TryDecode
is analogous to TryUnmarshal
. The only difference here is that Encode
and Decode
are methods to Encoder
and Decoder
types.
NewEncoder
takes in the io.Writer
interface and returns a new Encoder
type. NewDecoder
takes in the io.Reader
interface and returns a new Decoder
type. For this example, I passed in os.Stdout
for NewEncoder
and myFile
(which is of os.File
type) for NewDecoder
.
Now that we know how to use these functions, we can dive into how the two approaches differ under the hood.
Golang Marshal() and Unmarshal()
Let’s take a look at their implementation:
There is no ads to display, Please add some