github.com/kaptinlin/jsonschema@v0.4.6/constructor_test.go (about)

     1  package jsonschema_test
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/kaptinlin/jsonschema"
     8  )
     9  
    10  func Example_object() {
    11  	// Simple object schema using constructor API
    12  	schema := jsonschema.Object(
    13  		jsonschema.Prop("name", jsonschema.String(jsonschema.MinLen(1))),
    14  		jsonschema.Prop("age", jsonschema.Integer(jsonschema.Min(0))),
    15  		jsonschema.Required("name"),
    16  	)
    17  
    18  	// Valid data
    19  	data := map[string]interface{}{
    20  		"name": "Alice",
    21  		"age":  30,
    22  	}
    23  
    24  	result := schema.Validate(data)
    25  	fmt.Println("Valid:", result.IsValid())
    26  	// Output: Valid: true
    27  }
    28  
    29  func Example_complexSchema() {
    30  	// Complex nested schema with validation keywords
    31  	userSchema := jsonschema.Object(
    32  		jsonschema.Prop("name", jsonschema.String(
    33  			jsonschema.MinLen(1),
    34  			jsonschema.MaxLen(100),
    35  		)),
    36  		jsonschema.Prop("age", jsonschema.Integer(
    37  			jsonschema.Min(0),
    38  			jsonschema.Max(150),
    39  		)),
    40  		jsonschema.Prop("email", jsonschema.Email()),
    41  		jsonschema.Prop("address", jsonschema.Object(
    42  			jsonschema.Prop("street", jsonschema.String(jsonschema.MinLen(1))),
    43  			jsonschema.Prop("city", jsonschema.String(jsonschema.MinLen(1))),
    44  			jsonschema.Prop("zip", jsonschema.String(jsonschema.Pattern(`^\d{5}$`))),
    45  			jsonschema.Required("street", "city"),
    46  		)),
    47  		jsonschema.Prop("tags", jsonschema.Array(
    48  			jsonschema.Items(jsonschema.String()),
    49  			jsonschema.MinItems(1),
    50  			jsonschema.UniqueItems(true),
    51  		)),
    52  		jsonschema.Required("name", "email"),
    53  	)
    54  
    55  	// Test data
    56  	userData := map[string]interface{}{
    57  		"name":  "Alice",
    58  		"age":   30,
    59  		"email": "alice@example.com",
    60  		"address": map[string]interface{}{
    61  			"street": "123 Main St",
    62  			"city":   "Anytown",
    63  			"zip":    "12345",
    64  		},
    65  		"tags": []interface{}{"developer", "go"},
    66  	}
    67  
    68  	result := userSchema.Validate(userData)
    69  	if result.IsValid() {
    70  		fmt.Println("User data is valid")
    71  	} else {
    72  		for field, err := range result.Errors {
    73  			fmt.Printf("Error in %s: %s\n", field, err.Message)
    74  		}
    75  	}
    76  	// Output: User data is valid
    77  }
    78  
    79  func Example_arraySchema() {
    80  	// Array schema with validation keywords
    81  	numbersSchema := jsonschema.Array(
    82  		jsonschema.Items(jsonschema.Number(
    83  			jsonschema.Min(0),
    84  			jsonschema.Max(100),
    85  		)),
    86  		jsonschema.MinItems(1),
    87  		jsonschema.MaxItems(10),
    88  	)
    89  
    90  	validData := []interface{}{10, 20, 30}
    91  	result := numbersSchema.Validate(validData)
    92  	fmt.Println("Numbers valid:", result.IsValid())
    93  
    94  	invalidData := []interface{}{-5, 150} // Out of range
    95  	result = numbersSchema.Validate(invalidData)
    96  	fmt.Println("Invalid numbers valid:", result.IsValid())
    97  	// Output:
    98  	// Numbers valid: true
    99  	// Invalid numbers valid: false
   100  }
   101  
   102  func Example_enumAndConst() {
   103  	// Enum schema using enum keyword
   104  	statusSchema := jsonschema.Enum("active", "inactive", "pending")
   105  
   106  	result := statusSchema.Validate("active")
   107  	fmt.Println("Status valid:", result.IsValid())
   108  
   109  	// Const schema using const keyword
   110  	versionSchema := jsonschema.Const("1.0.0")
   111  
   112  	result = versionSchema.Validate("1.0.0")
   113  	fmt.Println("Version valid:", result.IsValid())
   114  	// Output:
   115  	// Status valid: true
   116  	// Version valid: true
   117  }
   118  
   119  func Example_oneOfAnyOf() {
   120  	// OneOf: exactly one schema must match
   121  	oneOfSchema := jsonschema.OneOf(
   122  		jsonschema.String(),
   123  		jsonschema.Integer(),
   124  	)
   125  
   126  	result := oneOfSchema.Validate("hello")
   127  	fmt.Println("OneOf string valid:", result.IsValid())
   128  
   129  	// AnyOf: at least one schema must match
   130  	anyOfSchema := jsonschema.AnyOf(
   131  		jsonschema.String(jsonschema.MinLen(5)),
   132  		jsonschema.Integer(jsonschema.Min(0)),
   133  	)
   134  
   135  	result = anyOfSchema.Validate("hi") // Matches integer rule (length < 5 but is string)
   136  	fmt.Println("AnyOf short string valid:", result.IsValid())
   137  	// Output:
   138  	// OneOf string valid: true
   139  	// AnyOf short string valid: false
   140  }
   141  
   142  func Example_conditionalSchema() {
   143  	// Conditional schema using if/then/else keywords
   144  	conditionalSchema := jsonschema.If(
   145  		jsonschema.Object(
   146  			jsonschema.Prop("type", jsonschema.Const("premium")),
   147  		),
   148  	).Then(
   149  		jsonschema.Object(
   150  			jsonschema.Prop("features", jsonschema.Array(jsonschema.MinItems(5))),
   151  		),
   152  	).Else(
   153  		jsonschema.Object(
   154  			jsonschema.Prop("features", jsonschema.Array(jsonschema.MaxItems(3))),
   155  		),
   156  	)
   157  
   158  	// Basic plan object
   159  	basicPlan := map[string]interface{}{
   160  		"type":     "basic",
   161  		"features": []interface{}{"feature1", "feature2"},
   162  	}
   163  
   164  	result := conditionalSchema.Validate(basicPlan)
   165  	fmt.Println("Basic plan valid:", result.IsValid())
   166  	// Output: Basic plan valid: true
   167  }
   168  
   169  func Example_convenienceFunctions() {
   170  	// Using convenience functions that apply format keywords
   171  	profileSchema := jsonschema.Object(
   172  		jsonschema.Prop("id", jsonschema.UUID()),
   173  		jsonschema.Prop("email", jsonschema.Email()),
   174  		jsonschema.Prop("website", jsonschema.URI()),
   175  		jsonschema.Prop("created", jsonschema.DateTime()),
   176  		jsonschema.Prop("score", jsonschema.PositiveInt()),
   177  	)
   178  
   179  	data := map[string]interface{}{
   180  		"id":      "550e8400-e29b-41d4-a716-446655440000",
   181  		"email":   "user@example.com",
   182  		"website": "https://example.com",
   183  		"created": "2023-01-01T00:00:00Z",
   184  		"score":   95,
   185  	}
   186  
   187  	result := profileSchema.Validate(data)
   188  	fmt.Println("Profile valid:", result.IsValid())
   189  	// Output: Profile valid: true
   190  }
   191  
   192  func Example_compatibilityWithJSON() {
   193  	// New code construction approach
   194  	codeSchema := jsonschema.Object(
   195  		jsonschema.Prop("name", jsonschema.String()),
   196  		jsonschema.Prop("age", jsonschema.Integer()),
   197  	)
   198  
   199  	// Existing JSON compilation approach
   200  	compiler := jsonschema.NewCompiler()
   201  	jsonSchema, err := compiler.Compile([]byte(`{
   202  		"type": "object",
   203  		"properties": {
   204  			"name": {"type": "string"},
   205  			"age": {"type": "integer"}
   206  		}
   207  	}`))
   208  	if err != nil {
   209  		log.Fatal(err)
   210  	}
   211  
   212  	data := map[string]interface{}{
   213  		"name": "Bob",
   214  		"age":  25,
   215  	}
   216  
   217  	// Both approaches work identically
   218  	result1 := codeSchema.Validate(data)
   219  	result2 := jsonSchema.Validate(data)
   220  
   221  	fmt.Println("Code schema valid:", result1.IsValid())
   222  	fmt.Println("JSON schema valid:", result2.IsValid())
   223  	// Output:
   224  	// Code schema valid: true
   225  	// JSON schema valid: true
   226  }
   227  
   228  func Example_schemaRegistration() {
   229  	// Create compiler for schema registration
   230  	compiler := jsonschema.NewCompiler()
   231  
   232  	// Create User schema with Constructor API
   233  	userSchema := jsonschema.Object(
   234  		jsonschema.ID("https://example.com/schemas/user"),
   235  		jsonschema.Prop("id", jsonschema.UUID()),
   236  		jsonschema.Prop("name", jsonschema.String(jsonschema.MinLen(1))),
   237  		jsonschema.Prop("email", jsonschema.Email()),
   238  		jsonschema.Required("id", "name", "email"),
   239  	)
   240  
   241  	// Register the schema
   242  	compiler.SetSchema("https://example.com/schemas/user", userSchema)
   243  
   244  	// Create Profile schema that references User schema
   245  	profileJSON := `{
   246  		"type": "object",
   247  		"properties": {
   248  			"user": {"$ref": "https://example.com/schemas/user"},
   249  			"bio": {"type": "string"},
   250  			"website": {"type": "string", "format": "uri"}
   251  		},
   252  		"required": ["user"]
   253  	}`
   254  
   255  	profileSchema, err := compiler.Compile([]byte(profileJSON))
   256  	if err != nil {
   257  		log.Fatal(err)
   258  	}
   259  
   260  	// Test with valid data
   261  	profileData := map[string]interface{}{
   262  		"user": map[string]interface{}{
   263  			"id":    "550e8400-e29b-41d4-a716-446655440000",
   264  			"name":  "Alice Johnson",
   265  			"email": "alice@example.com",
   266  		},
   267  		"bio":     "Software engineer",
   268  		"website": "https://alice.dev",
   269  	}
   270  
   271  	result := profileSchema.Validate(profileData)
   272  	fmt.Println("Profile with registered user schema valid:", result.IsValid())
   273  	// Output: Profile with registered user schema valid: true
   274  }