File: json-schema.md

package info (click to toggle)
glaze 6.5.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,948 kB
  • sloc: cpp: 121,839; sh: 99; ansic: 26; makefile: 13
file content (149 lines) | stat: -rw-r--r-- 4,819 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# JSON Schema

JSON Schema can automaticly be generated for serializable named types exposed via the meta system.

```c++
std::string schema = glz::write_json_schema<my_struct>();
```

This can be used for autocomplete, linting, and validation of user input/config files in editors like VS Code that support JSON Schema.

![autocomplete example](https://user-images.githubusercontent.com/9817348/199346159-8b127c7b-a9ac-49fe-b86d-71350f0e1b10.png)

![linting example](https://user-images.githubusercontent.com/9817348/199347118-ef7e9f74-ed20-4ff5-892a-f70ff1df23b5.png)

## Registering JSON Schema Metadata

By default `glz::write_json_schema` will write out your fields and types, but additional field may also be registered by specializing `glz::json_schema` or adding a `glaze_json_schema` to your struct.

Example:

```c++
struct meta_schema_t
{
   int x{};
   std::string file_name{};
   bool is_valid{};
};

template <>
struct glz::json_schema<meta_schema_t>
{
   schema x{.description = "x is a special integer", .minimum = 1};
   schema file_name{.description = "provide a file name to load"};
   schema is_valid{.description = "for validation"};
};
```

The `glz::json_schema` struct allows additional metadata like `minimum`, `maximum`, etc. to be specified for your fields.

Or you can define `glaze_json_schema` in your struct in the same manner:

```c++
struct local_schema_t
{
   int x{};
   std::string file_name{};
   bool is_valid{};

   struct glaze_json_schema
   {
      glz::schema x{.description = "x is a special integer", .minimum = 1};
      glz::schema file_name{.description = "provide a file name to load"};
      glz::schema is_valid{.description = "for validation"};
   };
};
```

## Required Fields

Glaze can automatically mark fields as required in the generated JSON schema based on their nullability and compile options.

### Automatic Required Fields

By default, when using the `error_on_missing_keys` option, non-nullable fields will be marked as required in the schema:

```c++
struct user_config
{
   std::string username{};  // required (non-nullable)
   std::optional<int> age{}; // optional (nullable)
   int id{};                 // required (non-nullable)
};

// Generate schema with required fields
auto schema = glz::write_json_schema<user_config, glz::opts{.error_on_missing_keys = true}>();
```

This will generate a schema with `"required": ["username", "id"]`.

### Custom Required Field Logic

You can override the default behavior by providing a custom `requires_key` function in your type's `glz::meta` specialization:

```c++
struct api_request
{
   std::string endpoint{};
   std::string api_key{};
   std::optional<std::string> optional_param{};
   std::string reserved_field{};  // internal use only
};

template <>
struct glz::meta<api_request>
{
   // Custom logic to determine which fields are required
   static constexpr bool requires_key(std::string_view key, bool is_nullable)
   {
      // Don't require fields starting with "reserved"
      if (key.starts_with("reserved")) {
         return false;
      }
      // All non-nullable fields are required
      return !is_nullable;
   }
};
```

The `requires_key` function receives:
- `key`: The name of the field being checked
- `is_nullable`: Whether the field type is nullable (e.g., `std::optional`, pointers)

**Important:** The `requires_key` customization point affects both:
1. **JSON Schema generation** - which fields are listed in the `"required"` array
2. **JSON parsing/validation** - which fields are validated as required when `error_on_missing_keys = true`

This allows fine-grained control over which fields are required, useful for:
- Excluding internal/reserved fields from requirements
- Making non-nullable fields optional without wrapping them in `std::optional`
- Making certain nullable fields required based on business logic
- Implementing complex validation rules

#### Example: Parsing with `requires_key`

```c++
struct my_struct {
   int required_field{};
   int optional_field{};  // Not std::optional, but we want it to be optional
};

template <>
struct glz::meta<my_struct> {
   static constexpr bool requires_key(std::string_view key, bool is_nullable) {
      if (key == "optional_field") {
         return false;  // Make this field optional
      }
      return !is_nullable;  // Default: non-nullable fields are required
   }
};

// Parsing works with error_on_missing_keys = true
std::string json = R"({"required_field":42})";  // optional_field is missing - OK!
my_struct obj;
auto ec = glz::read<glz::opts{.error_on_missing_keys = true}>(obj, json);
// Success! optional_field was not required due to requires_key
```

For more detailed information about field validation and the `requires_key` customization point, see [Field Validation](field-validation.md).