github.com/kaptinlin/jsonschema@v0.4.6/examples/custom-formats/main.go (about) 1 package main 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "math" 7 8 "github.com/kaptinlin/jsonschema" 9 ) 10 11 // --- OpenAPI Format Validators --- 12 13 // validateInt32 checks if the value is a valid 32-bit integer. 14 func validateInt32(v interface{}) bool { 15 switch val := v.(type) { 16 case int: 17 return val >= math.MinInt32 && val <= math.MaxInt32 18 case int32: 19 return true 20 case int64: 21 return val >= math.MinInt32 && val <= math.MaxInt32 22 case float64: 23 // Check if it's a whole number in valid range 24 return val == float64(int64(val)) && val >= math.MinInt32 && val <= math.MaxInt32 25 default: 26 return false 27 } 28 } 29 30 // validateInt64 checks if the value is a valid 64-bit integer. 31 func validateInt64(v interface{}) bool { 32 switch val := v.(type) { 33 case int, int32, int64: 34 return true 35 case float64: 36 // Check if it's a whole number 37 return val == float64(int64(val)) 38 default: 39 return false 40 } 41 } 42 43 // validateFloat checks if the value is a valid 32-bit float. 44 func validateFloat(v interface{}) bool { 45 switch val := v.(type) { 46 case float32: 47 return true 48 case float64: 49 return val >= -math.MaxFloat32 && val <= math.MaxFloat32 50 default: 51 return false 52 } 53 } 54 55 // validateDouble checks if the value is a valid 64-bit float (double). 56 func validateDouble(v interface{}) bool { 57 _, ok := v.(float64) 58 return ok 59 } 60 61 // validateByte checks if the value is a valid base64 string. 62 func validateByte(v interface{}) bool { 63 s, ok := v.(string) 64 if !ok { 65 return true 66 } 67 _, err := base64.StdEncoding.DecodeString(s) 68 return err == nil 69 } 70 71 // validateBinary always returns true, as it's for any binary data. 72 func validateBinary(v interface{}) bool { 73 _, ok := v.(string) 74 return ok 75 } 76 77 // validatePassword always returns true, as it's a hint for UI. 78 func validatePassword(v interface{}) bool { 79 _, ok := v.(string) 80 return ok 81 } 82 83 // registerOpenAPIFormats demonstrates how to register OpenAPI 3.0 built-in formats. 84 func registerOpenAPIFormats(c *jsonschema.Compiler) { 85 // Number formats (including integers) 86 c.RegisterFormat("int32", validateInt32, "number") 87 c.RegisterFormat("int64", validateInt64, "number") 88 c.RegisterFormat("float", validateFloat, "number") 89 c.RegisterFormat("double", validateDouble, "number") 90 91 // String formats 92 c.RegisterFormat("byte", validateByte, "string") 93 c.RegisterFormat("binary", validateBinary, "string") 94 c.RegisterFormat("password", validatePassword, "string") 95 96 // Note: `date` and `date-time` are standard formats already included in the library. 97 fmt.Println("Registered custom formats to support OpenAPI 3.0 built-ins.") 98 } 99 100 func main() { 101 // Create a new compiler and register OpenAPI formats 102 compiler := jsonschema.NewCompiler() 103 compiler.SetAssertFormat(true) // Enable format validation 104 registerOpenAPIFormats(compiler) 105 106 // Define a schema that uses OpenAPI formats 107 schemaBytes := []byte(`{ 108 "$schema": "https://json-schema.org/draft/2020-12/schema", 109 "title": "User Profile", 110 "type": "object", 111 "properties": { 112 "userId": { 113 "type": "number", 114 "format": "int64" 115 }, 116 "age": { 117 "type": "number", 118 "format": "int32" 119 }, 120 "avatar": { 121 "type": "string", 122 "format": "byte" 123 }, 124 "apiKey": { 125 "type": "string", 126 "format": "password" 127 } 128 }, 129 "required": ["userId", "age", "avatar"] 130 }`) 131 132 schema, err := compiler.Compile(schemaBytes) 133 if err != nil { 134 fmt.Printf("Error compiling schema: %s\n", err) 135 return 136 } 137 138 // --- Test with valid data --- 139 fmt.Println("\n--- 1. Validation with valid data ---") 140 validData := map[string]interface{}{ 141 "userId": 9223372036854775807, // Max int64 142 "age": 30, 143 "avatar": "SGVsbG8sIHdvcmxkIQ==", // "Hello, world!" in base64 144 "apiKey": "a-secret-key", 145 } 146 result := schema.Validate(validData) 147 fmt.Printf("Result: IsValid=%v\n", result.IsValid()) 148 149 // --- Test with invalid data --- 150 fmt.Println("\n--- 2. Validation with invalid data ---") 151 invalidData := map[string]interface{}{ 152 "userId": 9223372036854775807, 153 "age": 2147483648, // Exceeds max int32 154 "avatar": "this is not base64", // Not a valid base64 string 155 } 156 result = schema.Validate(invalidData) 157 fmt.Printf("Result: IsValid=%v\n", result.IsValid()) 158 if !result.IsValid() { 159 fmt.Println("Errors:") 160 for _, detail := range result.Details { 161 for _, err := range detail.Errors { 162 if err.Keyword == "format" { 163 fmt.Printf(" - Location: %s, Message: %s\n", detail.InstanceLocation, err.Message) 164 } 165 } 166 } 167 } 168 }