Ralph Caraveo
Ralph Caraveo

Reputation: 10225

In Go, can JSON marshaling of a well-defined type ever fail?

Given the following code:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, err := json.Marshal(&Employee{Id: 2})
    if err != nil {
        log.Fatal("Couldn't marshal the Employee")
    }

    fmt.Println(string(b))
}

Can checking for the error be reliably ignored using the _ placeholder since the Employee struct is well defined. Theoretically it should never fail, so begs the question is it a good practice to ignore this type of error and save a little on this type of boilerplate error checking?

Ignoring would look like so:

package main

import (
    "encoding/json"
    "fmt"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, _ := json.Marshal(&Employee{Id: 2})
    fmt.Println(string(b))
}

Upvotes: 12

Views: 413

Answers (2)

user6169399
user6169399

Reputation:

Error handling and Go:

Proper error handling is an essential requirement of good software.


Normally your code won't fail. but if user Adds this MarshalJSON method reciver to your type, it fails:

func (t *Employee) MarshalJSON() ([]byte, error) {
    if t.Id == 2 {
        return nil, fmt.Errorf("Forbiden Id = %d", t.Id)
    }
    data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
    return data, nil
}

This code Compiles, but fails on purpose just for Id == 2 (The Go Playground):

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, err := json.Marshal(&Employee{Id: 2})
    if err != nil {
        log.Fatal("Couldn't marshal the Employee", err)
    }

    fmt.Println(string(b))
}

func (t *Employee) MarshalJSON() ([]byte, error) {
    if t.Id == 2 {
        return nil, fmt.Errorf("Forbiden Id = %d", t.Id)
    }
    data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
    return data, nil
}

Also this code Compiles, but fails (The Go Playground):

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, err := json.Marshal(&Employee{Id: 2})
    if err != nil {
        log.Fatal("Couldn't marshal the Employee")
    }

    fmt.Println(string(b))
}

func (t Employee) MarshalJSON() ([]byte, error) {
    data := []byte(fmt.Sprint(t))
    return data, nil
}

Upvotes: 7

Jesse Amano
Jesse Amano

Reputation: 828

You can always write your own "wrapper" packages to compose behavior that might otherwise be boilerplate. For example, if you have a logging system set up, you might build a small package that looks like:

package json
import (
  "encoding/json"
  "log"
)
func TryMarshal(v interface{}) []byte {
  b, err := json.Marshal(v)
  if err != nil {
    log.Println(err)
    return nil
  }
  return b
}

Upvotes: 0

Related Questions