Remove fields from struct or hide them in JSON [SOLVED]


GOLANG Solutions, GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

Introduction

We have walked through some examples of working with JSON format in Golang. In today's article, I will guide you on removing fields from the struct or hiding them in JSON string. In the previous post, we already introduced the json package and UnMarshal() function for parsing JSON string to a struct:

Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions.

func Unmarshal(data []byte, v any) error: Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps, slices, and pointers as necessary, with the following additional rules:

To unmarshal JSON into a pointer, Unmarshal first handles the case of the JSON being the JSON literal null. In that case, Unmarshal sets the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into the value pointed at by the pointer. If the pointer is nil, Unmarshal allocates a new value for it to point to.

The encoding of each struct field can be customized by the format string stored under the "json" key in the struct field's tag. The format string gives the name of the field, possibly followed by a comma-separated list of options. The name may be empty in order to specify options without overriding the default field name.

 

Example 1: Parsing a JSON string to a struct

The code below demonstrates how to use the Unmarshal() function to convert a JSON string to a struct:

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name string
	Age  int
}

func main() {
	var user1 User
	jsonStr := `{"Name":"Anna","Age":22}`
	err := json.Unmarshal([]byte(jsonStr), &user1)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", user1)
}

 

Example 2: Always skip parsing a field in a struct

Use json:"-" tag to skip a field if what you want is to always skip it while encoding JSON string to a struct. Take note that this is not necessary if your field is not exported; the JSON encoder automatically ignores such fields. As discussed before, if the field starts with a lowercase letter, it will not be exported. Here is an example of using the json:"-" tag to skip a field when parsing JSON string to a struct:

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name string `json:"-"`
	Age  int
}

func main() {
	var user1 User
	jsonStr := `{"Name":"Anna","Age":22}`
	err := json.Unmarshal([]byte(jsonStr), &user1)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", user1)
}

Output:

{Name: Age:22}

json:"-" works both ways: parsing JSON string to a struct or a struct to a JSON string. The example below shows how it works when converting from a struct to a string. Even though the struct has the field, we won’t see it in the JSON output:

package main

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

type PersonCus struct {
	Name string
	Age  int `json:"-"`
}

func main() {
	person1 := PersonCus{
		Name: "Anna",
		Age:  21,
	}

	data, err := json.Marshal(person1)
	if err != nil {
		fmt.Println("An error occured: %v", err)
		os.Exit(1)
	}

	fmt.Println(string(data))
}

Output:

{"Name":"Anna"}

 

Example 3: Parsing JSON string to a map instead of a struct

We also can use a map[string]interface{} instead of a struct in this case. You can easily remove fields by calling the delete built-in on the map for the fields to remove.

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	var user1 map[string]interface{}
	jsonStr := `{"Name":"Anna","Age":22}`
	err := json.Unmarshal([]byte(jsonStr), &user1)
	if err != nil {
		fmt.Println("error:", err)
	}
	if _, ok := user1["Name"]; ok {
		delete(user1, "Name")
	}
	fmt.Printf("%+v", user1)
}

Output:

map[Age:22]

 

Example 4: Dynamic parsing fields with the json omitempty tag

The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.

Here is an example of how to use the omitempty tag to dynamically parse a struct to a JSON string. Remember that we only want to ignore the field of the struct if it’s empty.

package main

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

type PersonCus struct {
	Name    string  `json:"name,omitempty"`
	Age     int     `json:"age,omitempty"`
	Pointer *string `json:"pointer,omitempty"`
}

func main() {
	pointer := "pointer"

	person1 := PersonCus{
		Name:    "Anna",
		Age:     21,
		Pointer: &pointer,
	}

	data, err := json.Marshal(person1)
	if err != nil {
		fmt.Println("An error occured: %v", err)
		os.Exit(1)
	}

	fmt.Println(string(data))

	// ALL of those are considered empty by Go
	nilPerson := PersonCus{
		Name:    "",
		Age:     0,
		Pointer: nil,
	}

	dataNil, err := json.Marshal(nilPerson)
	if err != nil {
		fmt.Println("An error occured: %v", err)
		os.Exit(1)
	}

	fmt.Println(string(dataNil))
}

Output:

{"name":"Anna","age":21,"pointer":"yes"}
{}

The second struct contains nothing at all. The omitempty annotation causes all fields to be ignored since they are empty. It may seem contradictory at times, but zero-values and nil pointers are regarded as empty. If you actually want to use omitempty, you need to deal with something like *int64 if you want to produce a 0. The rest is pretty much just common sense.

 

Summary

In this article, I have provided some solutions to remove or hide fields on both sides: from JSON string to a struct or from a struct to a JSON string. Sometimes we have to handle missing fields while unmarshalling some JSON into a struct and got confused for a while. You can use the few examples above as a reminder of how most of it works. Those are not fancy edge cases. Those are self-contained, completely functional code snippets that should be easy to follow.

 

References

https://pkg.go.dev/encoding/json#Marshal
Removing fields from struct or hiding them in JSON Response

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment