patch

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2023 License: MIT Imports: 2 Imported by: 0

README

patch

This package aims to answer the question asked when implementing PATCH requests of RESTful API in Go:

Q: How to tell if a field is missing in the payload of a PATCH request?

Since we are using generics, Go 1.18+ is required.


Definition

Here we only talk about JSON payloads as it's the most frequently used format when developing a RESTful API.

Before implementaion, we need to define what is a missing field?

In this package, a field is defined as a missing field when:

  • if the name/key of the field is not found in the JSON object
  • or the name/key of the field is present but its value is null, null is interpreted as having no value

For example, in the following two JSON objects, field Name is missing:

{ "Age": 18 }
{ "Name": null, "Age": 18 }

A Go snippet example:

type UserPatch struct {
	Name   string
	Age    int
	Gender string
}

func PatchUser(rw http.ResponseWriter, r *http.Request) {
	var payload UserPatch
	json.NewDecoder(r.Body).Decode(&payload)

    // Both the requests `{"Name":"","Age":18}` and `{"Age":18}` can
    // cause `payload.Name == ""`.
    // ** How can we distinguish the two? **
    // "A field is missing" and "a field is empty" are semantically different.
	if payload.Name == "" {
		// do sth...
	}
}

Solution: add a sentinel to each field

Using patch.Field to define/wrap your fields in a struct.

import "github.com/ggicci/patch"

type UserPatch struct {
	Name   patch.Field[string]
	Age    patch.Field[int]
	Gender patch.Field[string]
}

func PatchUser(rw http.ResponseWriter, r *http.Request) {
	var payload UserPatch
	json.NewDecoder(r.Body).Decode(&payload)

	if !payload.Name.Valid {
		// error: field "Name" is missing (not found or null)
	}
}

Now we can tell a field is missing from a field is empty by consulting the sentinel Field.Valid:

  • when Field.Valid == false, then field is missing or is null
  • when Field.Valid == true, then field is provided and is not null

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Field

type Field[T any] struct {
	Value T
	Valid bool
}

Field is a wrapper which can tell if a field was unmarshalled from the data provided. When `Field.Valid` is true, which means `Field.Value` is populated from decoding the raw data. Otherwise, no data was provided, i.e. field missing.

func (*Field[T]) IsValid added in v1.0.0

func (f *Field[T]) IsValid() bool

func (Field[T]) MarshalJSON

func (f Field[T]) MarshalJSON() ([]byte, error)

func (*Field[T]) SetValid added in v1.0.0

func (f *Field[T]) SetValid(valid bool)

func (*Field[T]) UnmarshalJSON

func (f *Field[T]) UnmarshalJSON(data []byte) error

type ValidSentinel added in v1.0.0

type ValidSentinel interface {
	IsValid() bool
	SetValid(bool)
}

Jump to

Keyboard shortcuts

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