package module
Version: v1.0.1 Latest Latest

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

Go to latest
Published: Sep 7, 2023 License: Apache-2.0 Imports: 8 Imported by: 112



Build Status

This library is here to help you with all your data validation needs. It's ideally suited to writing tests against JSON-like structures, but can do much much more. We use it in elastic/beats for our own tests.


If using go modules edit go.mod, adding the following to your require list, replacing VERSION, with the latest version from our releases page.

require (
  github.com/elastic/go-lookslike VERSION

If using govendor run:

govendor fetch github.com/elastic/go-lookslike

Real World Usage Examples

lookslike was created to improve the testing of various structures in elastic/beats. Searching the tests for lookslike.MustCompile will show real world usage.

Call for More isdefs!

We currently define only the isdefs we've actually used in the field. If you'd like to add your own, please open a PR (with tests!).



Package lookslike is used to validate JSON-like nested map data-structure against a set of expectations. Its key features are allowing custom, function defined validators for values, and allowing the composition of multiple validation specs.

See the example below for more details. Most key functions include detailed examples of their use within this documentation.

// Let's say we want to validate this map
data := map[string]interface{}{"foo": "bar", "baz": "bot", "count": 1}

// We can validate the data by creating a lookslike.Validator
// validator.Validators are functions created by compiling the special lookslike.map[string]interface{}
// type. This is a map[string]interface{} that can be compiled
// into a series of checks.

// We can validate the data by defining a validator for this data.
//Lookslike has powerful matching features for maps and slices especially.
// You can see an example validator below:
validator := MustCompile(map[string]interface{}{
	"foo": isdef.IsStringContaining("a"),
	"baz": "bot",

// When being used in test-suites, you should use testslike.Test to execute the validator
// This produces easy to read test output, and outputs one failed assertion per failed matcher
// See the docs for testslike for more info.
// testslike.Test(t, validator, data)

// If you need more control than testslike.Test provides, you can use the results directly
results := validator(data)

// The Results.Valid property indicates if the validator passed
fmt.Printf("Results.Valid: %t\n", results.Valid)

// Results.Errors() returns one error per failed match
fmt.Printf("There were %d errors\n", len(results.Errors()))

// Results.Fields is a map of paths defined in the input map[string]interface{} to the result of their validation
// This is useful if you need more control
fmt.Printf("Over %d fields\n", len(results.Fields))

// You may be thinking that the validation above should have failed since there was an
// extra key, 'count', defined that was encountered. By default lookslike does not
// consider extra data to be an error. To change that behavior, wrap the validator
// in lookslike.Strict()
strictResults := Strict(validator)(data)

fmt.Printf("Strict Results.Valid: %t\n", strictResults.Valid)

// You can Check an exact field for an error
fmt.Printf("For the count field specifically .Valid is: %t\n", strictResults.Fields["count"][0].Valid)

// And get error objects for each error
for _, err := range strictResults.Errors() {

// And even get a new Results object with only invalid fields included




This section is empty.


This section is empty.


func Compose

func Compose(validators ...validator.Validator) validator.Validator

Compose combines multiple SchemaValidators into a single one.

// Composition is useful when you need to share common validation logic between validators.
// Let's imagine that we want to validate maps describing pets.

pets := []map[string]interface{}{
	{"Name": "rover", "barks": "often", "fur_length": "long"},
	{"Name": "lucky", "barks": "rarely", "fur_length": "short"},
	{"Name": "pounce", "meows": "often", "fur_length": "short"},
	{"Name": "peanut", "meows": "rarely", "fur_length": "long"},

// We can see that all pets have the "fur_length" property, but that only cats meow, and dogs bark.
// We can concisely encode this in lookslike using lookslike.Compose.
// We can also see that both "meows" and "barks" contain the same enums of values.
// We'll start by creating a composed IsDef using the IsAny composition, which creates a new IsDef that is
// a logical 'or' of its IsDef arguments

isFrequency := isdef.IsAny(isdef.IsEqual("often"), isdef.IsEqual("rarely"))

petValidator := MustCompile(map[string]interface{}{
	"Name":       isdef.IsNonEmptyString,
	"fur_length": isdef.IsAny(isdef.IsEqual("long"), isdef.IsEqual("short")),
dogValidator := Compose(
	MustCompile(map[string]interface{}{"barks": isFrequency}),
catValidator := Compose(
	MustCompile(map[string]interface{}{"meows": isFrequency}),

for _, pet := range pets {
	var petType string
	if dogValidator(pet).Valid {
		petType = "dog"
	} else if catValidator(pet).Valid {
		petType = "cat"
	fmt.Printf("%s is a %s\n", pet["Name"], petType)

rover is a dog
lucky is a dog
pounce is a cat
peanut is a cat

func MustCompile

func MustCompile(in interface{}) validator.Validator

MustCompile compiles the given validation, panic-ing if that map is invalid.

func Strict

func Strict(laxValidator validator.Validator) validator.Validator

Strict is used when you want any unspecified keys that are encountered to be considered errors.


type CompiledSchema

type CompiledSchema []flatValidator

CompiledSchema represents a compiled definition for driving a validator.Validator.

func (CompiledSchema) Check

func (cs CompiledSchema) Check(actual interface{}) *llresult.Results

Check executes the the checks within the CompiledSchema


Path Synopsis

Jump to

Keyboard shortcuts

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