github.com/kaptinlin/jsonschema@v0.4.6/docs/compilation.md (about) 1 # Schema Compilation Guide 2 3 Guide to compiling and configuring JSON Schemas. 4 5 ## Basic Compilation 6 7 ### Simple Schema 8 9 ```go 10 compiler := jsonschema.NewCompiler() 11 12 schema, err := compiler.Compile([]byte(`{ 13 "type": "object", 14 "properties": { 15 "name": {"type": "string"}, 16 "age": {"type": "integer", "minimum": 0} 17 }, 18 "required": ["name"] 19 }`)) 20 21 if err != nil { 22 log.Fatal(err) 23 } 24 ``` 25 26 ### Schema with ID 27 28 ```go 29 // Compile with specific ID for referencing 30 schema, err := compiler.CompileWithID("user.json", []byte(`{ 31 "$id": "user.json", 32 "type": "object", 33 "properties": { 34 "name": {"type": "string"}, 35 "email": {"type": "string", "format": "email"} 36 } 37 }`)) 38 ``` 39 40 --- 41 42 ## Compiler Configuration 43 44 ### Format Validation 45 46 Enable format assertions (email, date-time, etc.): 47 48 ```go 49 compiler := jsonschema.NewCompiler() 50 compiler.SetAssertFormat(true) 51 52 schema, _ := compiler.Compile([]byte(`{ 53 "type": "object", 54 "properties": { 55 "email": {"type": "string", "format": "email"}, 56 "created": {"type": "string", "format": "date-time"} 57 } 58 }`)) 59 ``` 60 61 ### Base URI 62 63 Set default base URI for schema references: 64 65 ```go 66 compiler.SetDefaultBaseURI("https://example.com/schemas/") 67 68 // Now relative $refs resolve against this base 69 schema, _ := compiler.Compile([]byte(`{ 70 "type": "object", 71 "properties": { 72 "user": {"$ref": "user.json"} 73 } 74 }`)) 75 ``` 76 77 --- 78 79 ## Custom Formats 80 81 ### Register Format Validators 82 83 ```go 84 compiler := jsonschema.NewCompiler() 85 86 // UUID format 87 compiler.RegisterFormat("uuid", func(value string) bool { 88 _, err := uuid.Parse(value) 89 return err == nil 90 }) 91 92 // Custom phone number format 93 compiler.RegisterFormat("phone", func(value string) bool { 94 return len(value) >= 10 && regexp.MustCompile(`^\+?[0-9\-\s]+$`).MatchString(value) 95 }) 96 97 // Date format (YYYY-MM-DD) 98 compiler.RegisterFormat("date", func(value string) bool { 99 _, err := time.Parse("2006-01-02", value) 100 return err == nil 101 }) 102 ``` 103 104 ### Using Custom Formats 105 106 ```go 107 schema, _ := compiler.Compile([]byte(`{ 108 "type": "object", 109 "properties": { 110 "id": {"type": "string", "format": "uuid"}, 111 "phone": {"type": "string", "format": "phone"}, 112 "birthdate": {"type": "string", "format": "date"} 113 } 114 }`)) 115 ``` 116 117 --- 118 119 ## Schema References 120 121 ### Local References 122 123 ```go 124 schema, _ := compiler.Compile([]byte(`{ 125 "$defs": { 126 "address": { 127 "type": "object", 128 "properties": { 129 "street": {"type": "string"}, 130 "city": {"type": "string"} 131 } 132 } 133 }, 134 "type": "object", 135 "properties": { 136 "home": {"$ref": "#/$defs/address"}, 137 "work": {"$ref": "#/$defs/address"} 138 } 139 }`)) 140 ``` 141 142 ### External References 143 144 ```go 145 // First, register the referenced schema 146 compiler.CompileWithID("address.json", []byte(`{ 147 "type": "object", 148 "properties": { 149 "street": {"type": "string"}, 150 "city": {"type": "string"}, 151 "country": {"type": "string", "default": "US"} 152 }, 153 "required": ["street", "city"] 154 }`)) 155 156 // Then reference it in another schema 157 mainSchema, _ := compiler.Compile([]byte(`{ 158 "type": "object", 159 "properties": { 160 "name": {"type": "string"}, 161 "address": {"$ref": "address.json"} 162 } 163 }`)) 164 ``` 165 166 ### Dynamic References 167 168 ```go 169 // Recursive schema with $dynamicRef 170 schema, _ := compiler.Compile([]byte(`{ 171 "$id": "tree.json", 172 "$defs": { 173 "node": { 174 "type": "object", 175 "properties": { 176 "value": {"type": "string"}, 177 "children": { 178 "type": "array", 179 "items": {"$dynamicRef": "#node"} 180 } 181 } 182 } 183 }, 184 "$ref": "#/$defs/node" 185 }`)) 186 ``` 187 188 --- 189 190 ## JSON Library Configuration 191 192 ### High-Performance JSON Libraries 193 194 Use faster JSON libraries for better performance: 195 196 ```go 197 import "github.com/bytedance/sonic" 198 199 compiler := jsonschema.NewCompiler() 200 201 // Use sonic for JSON operations 202 compiler.WithEncoderJSON(sonic.Marshal) 203 compiler.WithDecoderJSON(sonic.Unmarshal) 204 ``` 205 206 ### Custom JSON Functions 207 208 ```go 209 // Custom marshal function 210 compiler.WithEncoderJSON(func(v interface{}) ([]byte, error) { 211 // Your custom marshal logic 212 return json.Marshal(v) 213 }) 214 215 // Custom unmarshal function 216 compiler.WithDecoderJSON(func(data []byte, v interface{}) error { 217 // Your custom unmarshal logic 218 return json.Unmarshal(data, v) 219 }) 220 ``` 221 222 --- 223 224 ## Schema Loaders 225 226 ### Custom Schema Loaders 227 228 Register custom loaders for different protocols: 229 230 ```go 231 // HTTP loader 232 compiler.RegisterLoader("http", func(url string) ([]byte, error) { 233 resp, err := http.Get(url) 234 if err != nil { 235 return nil, err 236 } 237 defer resp.Body.Close() 238 return io.ReadAll(resp.Body) 239 }) 240 241 // File loader 242 compiler.RegisterLoader("file", func(url string) ([]byte, error) { 243 return os.ReadFile(strings.TrimPrefix(url, "file://")) 244 }) 245 ``` 246 247 ### Using Custom Loaders 248 249 ```go 250 // Schema will be loaded via HTTP 251 schema, _ := compiler.Compile([]byte(`{ 252 "type": "object", 253 "properties": { 254 "user": {"$ref": "http://example.com/schemas/user.json"} 255 } 256 }`)) 257 ``` 258 259 --- 260 261 ## Advanced Configuration 262 263 ### Media Type Handlers 264 265 Register custom media type handlers: 266 267 ```go 268 // YAML handler 269 compiler.RegisterMediaType("application/yaml", func(data []byte) (interface{}, error) { 270 var result interface{} 271 err := yaml.Unmarshal(data, &result) 272 return result, err 273 }) 274 ``` 275 276 ### Multiple Schemas 277 278 Compile multiple related schemas: 279 280 ```go 281 compiler := jsonschema.NewCompiler() 282 283 // User schema 284 compiler.CompileWithID("user.json", []byte(`{ 285 "type": "object", 286 "properties": { 287 "id": {"type": "string"}, 288 "name": {"type": "string"}, 289 "email": {"type": "string", "format": "email"} 290 } 291 }`)) 292 293 // Post schema referencing user 294 compiler.CompileWithID("post.json", []byte(`{ 295 "type": "object", 296 "properties": { 297 "id": {"type": "string"}, 298 "title": {"type": "string"}, 299 "author": {"$ref": "user.json"} 300 } 301 }`)) 302 303 // Get compiled schemas 304 userSchema, _ := compiler.GetSchema("user.json") 305 postSchema, _ := compiler.GetSchema("post.json") 306 ``` 307 308 --- 309 310 ## Error Handling 311 312 ### Compilation Errors 313 314 ```go 315 schema, err := compiler.Compile(invalidSchemaBytes) 316 if err != nil { 317 switch { 318 case strings.Contains(err.Error(), "invalid JSON"): 319 log.Printf("Schema JSON syntax error: %v", err) 320 case strings.Contains(err.Error(), "unresolved reference"): 321 log.Printf("Schema reference error: %v", err) 322 default: 323 log.Printf("Schema compilation error: %v", err) 324 } 325 } 326 ``` 327 328 ### Reference Resolution Errors 329 330 ```go 331 schema, err := compiler.Compile([]byte(`{ 332 "type": "object", 333 "properties": { 334 "user": {"$ref": "missing-schema.json"} 335 } 336 }`)) 337 338 if err != nil { 339 log.Printf("Failed to resolve schema reference: %v", err) 340 } 341 ``` 342 343 --- 344 345 ## Performance Tips 346 347 ### Compilation Best Practices 348 349 1. **Reuse compiler instances** for related schemas 350 2. **Pre-compile schemas** at application startup 351 3. **Use specific IDs** for schemas you'll reference 352 4. **Register custom formats** before compilation 353 5. **Set base URI** for relative references 354 355 ```