structify

package module
v0.0.0-...-dd25d3a Latest Latest
Warning

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

Go to latest
Published: Feb 18, 2023 License: MIT Imports: 7 Imported by: 2

README

Go Reference Build Status

structify

structify is designed to parse loosely-typed, client-controlled input such as JSON or a web form submission into a struct. It's purpose is to validate input shape and convert to a struct, not to validate input contents. For example, validating and converting an input field to an integer, not validating that the integer is between 0 and 10.

Example Usage

type Person struct {
  FirstName string
  LastName string
}

var person Person
err := structify.Parse(map[string]any{"FirstName": "John", "LastName": "Smith"}, &person)

Features

  • Supports nested structs
  • Supports slices
  • Automatically maps between camelcase and snakecase. That is, first_name will be mapped to FirstName without needing a struct field tag
  • Structured errors that accumulate all field errors
  • Automatically uses database/sql.Scanner interface if available
  • Can define scanner method on types or register on parser when not convenient to add method to type
  • Includes generic Optional type

Documentation

Overview

Package structify parses loosely-typed data into structs.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrCannotConvertToFloat      = errors.New("cannot convert to float")
	ErrCannotConvertToInteger    = errors.New("cannot convert to integer")
	ErrMissing                   = errors.New("missing value")
	ErrOutOfRange                = errors.New("out of range")
	ErrUnsupportedTypeConversion = errors.New("unsupported type conversion")
)

Functions

func Parse

func Parse(m map[string]any, target any) error

Parse delegates to DefaultParser. It is a simple convenience function for when no custom parse logic is needed. Parse is safe for concurrent usage.

Types

type AssignmentError

type AssignmentError struct {
	Source     any
	TargetType reflect.Type
	Err        error
}

AssignmentError represents an error that occurred assigning a value.

func (*AssignmentError) Error

func (e *AssignmentError) Error() string

func (*AssignmentError) Unwrap

func (e *AssignmentError) Unwrap() error

type MissingFieldScanner

type MissingFieldScanner interface {
	ScanMissingField()
}

MissingFieldScanner allows a field to be missing from the source data.

type Optional

type Optional[T any] struct {
	Value   T
	Present bool
}

Optional wraps any type and allows it to be missing from the source data.

func (*Optional[T]) ScanMissingField

func (opt *Optional[T]) ScanMissingField()

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser is a type that can parse simple types into structs.

var DefaultParser *Parser

func (*Parser) Parse

func (p *Parser) Parse(source, target any) error

Parse parses source into target. source may be any string type, integer type, float type, bool, map[string]any, map[string]string, []any, or slice that can be converted to []any, or nil. target must be a pointer. source and target must be compatible types such as map[string]any and pointer to struct.

By default, all fields in a target struct must be present in source. Optional fields must implement the MissingFieldScanner interface. This can be done in a generic fashion with the Optional type.

Example (Struct)
package main

import (
	"fmt"

	"github.com/jackc/structify"
)

func main() {
	var person struct {
		Name      string
		Age       int16
		Inventory []string `structify:"items"`
		Skip      string   `structify:"-"`
	}

	parser := &structify.Parser{}
	err := parser.Parse(map[string]any{"name": "John", "age": 21, "items": []string{"watch", "wallet"}}, &person)
	if err != nil {
		fmt.Printf("parser.Parse error: %v", err)
		return
	}

	fmt.Println(person.Name, person.Age, person.Inventory)

}
Output:

John 21 [watch wallet]

func (*Parser) RegisterTypeScanner

func (p *Parser) RegisterTypeScanner(value any, fn TypeScannerFunc)

RegisterTypeScanner configures parser to call fn for any scan target with the same type as value.

type Scanner

type Scanner interface {
	Scan(value any) error
}

Scanner matches the database/sql.Scanner interface. It allows many database/sql types to be used without needing to implement any structify interfaces. If a type does need to implement custom scanning logic for structify prefer the StructifyScanner interface.

type StructifyScanner

type StructifyScanner interface {
	// StructifyScan scans source into itself. source may be string, int64, float64, bool, map[string]any, []any, or nil.
	StructifyScan(parser *Parser, source any) error
}

StructifyScanner allows a type to control how it is parsed.

type TypeScannerFunc

type TypeScannerFunc func(parser *Parser, source, target any) error

TypeScannerFunc parses source and assigns it to target.

Jump to

Keyboard shortcuts

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