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  ```