The following column golang tutorial will introduce to you how to use JSON time to distinguish empty fields and unset fields in How to differentiate between empty fields and unset fields when using JSON in Golanglang. I hope it will be helpful to friends in need!
A few weeks ago, I was working on a How to differentiate between empty fields and unset fields when using JSON in Golanglang microservice and needed to add support for CURP operations using JSON data. Typically, I would create a struct for the entity. All fields and the 'omitempty' attribute are defined in the body, as shown below
type Article struct { Id string `json:"id"` Name string `json:"name,omitempty"` Desc string `json:"desc,omitempty"` }
Problem
But this representation brings serious problems, especially for Update Or Edit operation.
For example, suppose the JSON data of the update request looks like this
{"id":"1234","name":"xyz","desc":""}
Note the empty desc field. Now let us take a look at the request data in What does it look like after unblocking in How to differentiate between empty fields and unset fields when using JSON in Golang
func Test_JSON1(t *testing.T) { jsonData:=`{"id":"1234","name":"xyz","desc":""}` req:=Article{} _=json.Unmarshal([]byte(jsonData),&req) fmt.Printf("%+v",req) }Output: === RUN Test_JSON1 {Id:1234 Name:xyz Desc:}
The description here is an empty string. Obviously the client wants to set desc to an empty string, which is inferred by our program.
However, if the client does not wish to change the existing value of Desc, in which case it is incorrect to send a description string again, so the requested JSON data may look like this
{"id":"1234","name":"xyz"}
We unblock it into our structure
func Test_JSON2(t *testing.T) { jsonData:=`{"id":"1234","name":"xyz"}` req:=Article{} _=json.Unmarshal([]byte(jsonData),&req) fmt.Printf("%+v",req) }Output: === RUN Test_JSON2 {Id:1234 Name:xyz Desc:}
Well, Desc will still be Obtained as an empty string, so how to distinguish between unset fields and empty fields
Short answer? Pointers
Solution
Subject to some Inspired by existing How to differentiate between empty fields and unset fields when using JSON in Golanglang libraries like go-github. We can change the struct fields to pointer types as shown below
type Article struct { Id string `json:"id"` Name *string `json:"name,omitempty"` Desc *string `json:"desc,omitempty"` }
By doing this, we add additional status. If the field does not exist in the original JSON, the structure field will be empty (nil).
On the other hand, if the field does exist and is null, then the pointer is not null and the field contains a null value.
Note - I did not change the 'Id' field to a pointer type because It does not have an empty status, the id is required, similar to the id in the database.
Let’s try again.
func Test_JSON_Empty(t *testing.T) { jsonData := `{"id":"1234","name":"xyz","desc":""}` req := Article{} _ = json.Unmarshal([]byte(jsonData), &req) fmt.Printf("%+v\n", req) fmt.Printf("%s\n", *req.Name) fmt.Printf("%s\n", *req.Desc) } func Test_JSON_Nil(t *testing.T) { jsonData := `{"id":"1234","name":"xyz"}` req := Article{} _ = json.Unmarshal([]byte(jsonData), &req) fmt.Printf("%+v\n", req) fmt.Printf("%s\n", *req.Name) }
Output
=== RUN Test_JSON_Empty {Id:1234 Name:0xc000088540 Desc:0xc000088550} Name: xyz Desc: --- PASS: Test_JSON_Empty (0.00s)=== RUN Test_JSON_Nil {Id:1234 Name:0xc00005c590 Desc:<nil>} Name: xyz --- PASS: Test_JSON_Nil (0.00s)
The first case , since desc is set to an empty string, we get a non-null pointer in Desc and contains the value of an empty string. In the second case, the field is not set, and we get a null character String pointer.
So we can distinguish two types of updates. This method not only applies to strings, but also to all other data types, including integers, nested structures, etc.
But there are also some problems with this approach.
Null safety: Non-pointer data types have inherent null safety. In How to differentiate between empty fields and unset fields when using JSON in Golanglang this means string or Integers can never be null. They always have a default value. But if pointers are defined, these data types default to null unless set manually. Therefore, attempts to access those pointers without verifying nullability data may cause the application to crash.
# 以下代码将崩溃, 因为 desc 为空 func Test_JSON_Nil(t *testing.T) { jsonData := `{"id":"1234","name":"xyz"}` req := Article{} _ = json.Unmarshal([]byte(jsonData), &req) fmt.Printf("%+v\n", req) fmt.Printf("%s\n", *req.Desc) }
This problem can be easily solved by always checking for a null pointer, but your code may look verbose.
Yes Printability: As you may have noticed in the output of the pointer-based solution, the value of the pointer is not printed. Twenty prints the hexadecimal value of the pointer, which is of little use in the application . This can also be overcome by re-using the stringer interface.
func (a *Article) String() string { output:=fmt.Sprintf("Id: %s ",a.Id) if a.Name!=nil{ output+=fmt.Sprintf("Name: '%s' ",*a.Name) } if u.Desc!=nil{ output+=fmt.Sprintf("Desc: '%s' ",u.Desc) } return output }
Appendix:
Original address: https://medium.com/@arpitkh96/differentiate-between-empty-and-not-set-fields-with-json-in-golang-957bb2c5c065
Translation address: https://learnku.com/go/t/49332
The above is the detailed content of How to differentiate between empty fields and unset fields when using JSON in Golang. For more information, please follow other related articles on the PHP Chinese website!