jsontype

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 3, 2023 License: Apache-2.0 Imports: 9 Imported by: 19

README

Go Report Card Go Reference

jsontype

This package provides a generic json.Marshaler and json.Unmarshaler wrapper for common Go types. This helps minimize custom JSON string parsing and formatting code.

import "github.com/MicahParks/jsontype"

Supported Types

  1. *mail.Address
  2. *regexp.Regexp
  3. time.Time
  4. time.Duration
  5. *url.URL

Planned support

  1. *big.Float
  2. *big.Int
  3. *big.Rat
  4. netip.Addr
  5. netip.AddrPort
  6. netip.Prefix

Usage

  • All methods are safe for concurrent use by multiple goroutines.

Define a data structure using one or more *jsontype.JSONType generic field.

type myConfig struct {
	Ends            *jsontype.JSONType[time.Time]      `json:"ends"`
	GetInterval     *jsontype.JSONType[time.Duration]  `json:"getInterval"`
	NotificationMsg string                             `json:"notificationMsg"`
	Notify          *jsontype.JSONType[*mail.Address]  `json:"notify"`
	TargetPage      *jsontype.JSONType[*url.URL]       `json:"targetPage"`
	TargetRegExp    *jsontype.JSONType[*regexp.Regexp] `json:"targetRegExp"`
}

Optionally set non-default behavior through options before unmarshalling

// Set non-default unmarshal behavior.
endOpts := jsontype.Options{
	TimeFormatUnmarshal: time.RFC1123,
}
config.Ends = jsontype.NewWithOptions(time.Time{}, endOpts)

Unmarshal JSON into the data structure

// Unmarshal the configuration.
err := json.Unmarshal(json.RawMessage(exampleConfig), &config)
if err != nil {
	logger.Fatalf("failed to unmarshal JSON: %s", err)
}

Use the fields on the data structure by accessing the .Get() method

// Access fields on the unmarshalled configuration.
logger.Printf("Ends: %s", config.Ends.Get().String())
logger.Printf("Get interval: %s", config.GetInterval.Get().String())

Optionally set non-default behavior through options before marshalling

// Set non-default marshal behavior.
emailOpts := jsontype.Options{
	MailAddressAddressOnlyMarshal: true,
	MailAddressLowerMarshal:       true,
}
config.Notify = jsontype.NewWithOptions(config.Notify.Get(), emailOpts)

Marshal the data structure into JSON

// Marshal the configuration back to JSON.
remarshaled, err := json.MarshalIndent(config, "", "  ")
if err != nil {
	logger.Fatalf("failed to re-marshal configuration: %s", err)
}

Examples

Please see the examples directory.

package main

import (
	"encoding/json"
	"log"
	"net/mail"
	"net/url"
	"os"
	"regexp"
	"time"

	"github.com/MicahParks/jsontype"
)

const exampleConfig = `{
  "ends": "Wed, 04 Oct 2022 00:00:00 MST",
  "getInterval": "1h30m",
  "notificationMsg": "Your item is on sale!",
  "notify": "EXAMPLE@example.com",
  "targetPage": "https://www.example.com",
  "targetRegExp": "example"
}`

type myConfig struct {
	Ends            *jsontype.JSONType[time.Time]      `json:"ends"`
	GetInterval     *jsontype.JSONType[time.Duration]  `json:"getInterval"`
	NotificationMsg string                             `json:"notificationMsg"`
	Notify          *jsontype.JSONType[*mail.Address]  `json:"notify"`
	TargetPage      *jsontype.JSONType[*url.URL]       `json:"targetPage"`
	TargetRegExp    *jsontype.JSONType[*regexp.Regexp] `json:"targetRegExp"`
}

func main() {
	logger := log.New(os.Stdout, "", 0)
	var config myConfig

	// Set non-default unmarshal behavior.
	endOpts := jsontype.Options{
		TimeFormatUnmarshal: time.RFC1123,
	}
	config.Ends = jsontype.NewWithOptions(time.Time{}, endOpts)

	// Unmarshal the configuration.
	err := json.Unmarshal(json.RawMessage(exampleConfig), &config)
	if err != nil {
		logger.Fatalf("failed to unmarshal JSON: %s", err)
	}

	// Access fields on the unmarshalled configuration.
	logger.Printf("Ends: %s", config.Ends.Get().String())
	logger.Printf("Get interval: %s", config.GetInterval.Get().String())

	// Set non-default marshal behavior.
	emailOpts := jsontype.Options{
		MailAddressAddressOnlyMarshal: true,
		MailAddressLowerMarshal:       true,
	}
	config.Notify = jsontype.NewWithOptions(config.Notify.Get(), emailOpts)

	// Marshal the configuration back to JSON.
	remarshaled, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		logger.Fatalf("failed to re-marshal configuration: %s", err)
	}
	logger.Println(string(remarshaled))
}

Output:

Ends: 2022-10-04 00:00:00 -0500 -0500
Get interval: 1h30m0s
{
  "ends": "2022-10-04T00:00:00-05:00",
  "getInterval": "1h30m0s",
  "notificationMsg": "Your item is on sale!",
  "notify": "example@example.com",
  "targetPage": "https://www.example.com",
  "targetRegExp": "example"
}

Testing

$ go test -cover -race
PASS
coverage: 90.1% of statements
ok      github.com/MicahParks/jsontype  0.021s

Documentation

Index

Constants

View Source
const (
	// EnvVarConfigJSON is the environment variable that can be used to provide the JSON configuration for the Read
	// function.
	EnvVarConfigJSON = "CONFIG_JSON"
	// EnvVarConfigPath is the environment variable that can be used to provide the path to the JSON configuration file
	// for the Read function.
	EnvVarConfigPath = "CONFIG_PATH"
)

Variables

View Source
var ErrDefaultsAndValidate = errors.New("jsontype: failed to apply defaults and validate configuration")

ErrDefaultsAndValidate is the error returned by the DefaultsAndValidate function when it fails to apply defaults and validate the configuration.

Functions

func Read added in v0.1.0

func Read[T Defaulter[T]]() (T, error)

Read is a convenience function to read JSON configuration. It will first check the environment variable in the EnvVarConfigJSON for raw JSON, then it will check the environment variable in the EnvVarConfigPath for the path to a JSON file. If neither are set, it will attempt to read "config.json" in the current working directory. If that file does not exist, it will return an os.ErrNotExist error.

Types

type Defaulter added in v0.6.0

type Defaulter[T any] interface {
	// DefaultsAndValidate applies default values and validates the data structure. If this function has an error, it
	// returns an error that can be checked with errors.Is to match ErrDefaultsAndValidate.
	//
	// For example, if a zero value is left for a *jsontype.JSONType[time.Duration], the default value can be set here.
	DefaultsAndValidate() (T, error)
}

Defaulter is any data structure that can unmarshalled from JSON that has defaults and can be validated.

type J

type J interface {
	*mail.Address | *regexp.Regexp | time.Duration | time.Time | *url.URL
}

J is a set of common Go types that can be marshaled and unmarshalled with this package.

type JSONType

type JSONType[T J] struct {
	// contains filtered or unexported fields
}

JSONType holds a generic J value. It can be used to marshal and unmarshal its value to and from JSON.

func New

func New[T J](v T) *JSONType[T]

New creates a new JSONType.

func NewWithOptions

func NewWithOptions[T J](v T, options Options) *JSONType[T]

NewWithOptions creates a new JSONType with options.

func (*JSONType[T]) Get

func (j *JSONType[T]) Get() T

Get returns the held value.

func (*JSONType[T]) MarshalJSON

func (j *JSONType[T]) MarshalJSON() ([]byte, error)

MarshalJSON helps implement the json.Marshaler interface.

func (*JSONType[T]) UnmarshalJSON

func (j *JSONType[T]) UnmarshalJSON(bytes []byte) error

UnmarshalJSON helps implement the json.Unmarshaler interface.

type Options

type Options struct {
	MailAddressAddressOnlyMarshal bool
	MailAddressLowerMarshal       bool
	MailAddressUpperMarshal       bool
	TimeFormatMarshal             string
	TimeFormatUnmarshal           string
}

Options is a set of options for a JSONType. It modifies the behavior of JSON marshal/unmarshal.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL