Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go JSON: How do you represent a JSON field in Go that could be absent, null or have a value? #4

Open
ryan961 opened this issue Jan 18, 2024 · 4 comments
Labels
Golang All things associated with Go. JSON Reading Daily Reading

Comments

@ryan961
Copy link
Owner

ryan961 commented Jan 18, 2024

🤖️ AI Summary

The article discusses handling JSON fields in Go that can be absent, null, or have a value. It presents a challenge when differentiating between fields that are unspecified or explicitly set to null. The solution involves a custom type Nullable[T] that uses a map to represent three states: field not set, set to null, or set to a value. This approach, avoiding the use of pointers, allows clear distinction between these states during JSON marshaling and unmarshaling.

🖇️ Details

📝 Note

// Code taken from https://github.com/oapi-codegen/nullable/blob/v1.0.0/nullable.go

// Nullable is a generic type, which implements a field that can be one of three states:
//
// - field is not set in the request
// - field is explicitly set to `null` in the request
// - field is explicitly set to a valid value in the request
//
// Nullable is intended to be used with JSON marshalling and unmarshalling.
//
// Internal implementation details:
//
// - map[true]T means a value was provided
// - map[false]T means an explicit null was provided
// - nil or zero map means the field was not provided
//
// If the field is expected to be optional, add the `omitempty` JSON tags. Do NOT use `*Nullable`!
//
// Adapted from https://github.com/golang/go/issues/64515#issuecomment-1841057182
type Nullable[T any] map[bool]T

// other fields and methods omitted

func (t Nullable[T]) MarshalJSON() ([]byte, error) {
	// if field was specified, and `null`, marshal it
	if t.IsNull() {
		return []byte("null"), nil
	}

	// if field was unspecified, and `omitempty` is set on the field's tags, `json.Marshal` will omit this field

	// otherwise: we have a value, so marshal it
	return json.Marshal(t[true])
}

func (t *Nullable[T]) UnmarshalJSON(data []byte) error {
	// if field is unspecified, UnmarshalJSON won't be called

	// if field is specified, and `null`
	if bytes.Equal(data, []byte("null")) {
		t.SetNull()
		return nil
	}
	// otherwise, we have an actual value, so parse it
	var v T
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}
	t.Set(v)
	return nil
}
@ryan961 ryan961 added Golang All things associated with Go. JSON labels Jan 18, 2024
@ryan961
Copy link
Owner Author

ryan961 commented Jan 18, 2024

📦 Package

github.com/oapi-codegen/nullable

🤖️ AI Intro

This package provides tools and code functionalities for managing nullable values during JSON marshaling and unmarshaling.. In situations where data might not have a definite value, this repository offers mechanisms to handle those values, reducing possibilities of errors or bugs in your project. By incorporating this repository into your work, you can have a consistent and strong handling of nullable values.

📝 Example

package main

import (
	"encoding/json"
	"fmt"

	"github.com/oapi-codegen/nullable"
)

func main() {
	obj := struct {
		Name nullable.Nullable[string] `json:"name"`
	}{}

	// when it's not set
	err := json.Unmarshal([]byte(`
		{
		}
		`), &obj)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Println("Unspecified:")
	fmt.Printf("obj.Name.IsSpecified(): %v\n", obj.Name.IsSpecified())
	fmt.Printf("obj.Name.IsNull(): %v\n", obj.Name.IsNull())
	fmt.Println("---")
}

🧭 Related

@ryan961 ryan961 added the Reading Daily Reading label Jan 23, 2024
@ryan961 ryan961 changed the title JSON: How do you represent a JSON field in Go that could be absent, null or have a value? Go JSON: How do you represent a JSON field in Go that could be absent, null or have a value? Jan 26, 2024
@blackstorm
Copy link

blackstorm commented Jan 27, 2024

Hi Ryan961,

What AI summarization tool did you use for this article? Have you tried Gitblog's AI meta generator tool?

AI SEO Metadata Generator

@ryan961
Copy link
Owner Author

ryan961 commented Jan 27, 2024

@blackstorm hi~ I've implemented the information in the 🤖️ AI Summary section based on coze.Thanks for your provision of the Gitblog tool and the AI meta generator tool. I'm looking forward to trying them out later.😄

@blackstorm
Copy link

@blackstorm hi~ I've implemented the information in the 🤖️ AI Summary section based on coze.Thanks for your provision of the Gitblog tool and the AI meta generator tool. I'm looking forward to trying them out later.😄

Thanks Ryan!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Golang All things associated with Go. JSON Reading Daily Reading
Projects
None yet
Development

No branches or pull requests

2 participants