|
| 1 | +--- |
| 2 | +layout: page |
| 3 | +title: Generating Code from JSON Schema |
| 4 | +bookmark: Basics |
| 5 | +permalink: /schema/:title/ |
| 6 | +icon: fas fa-tag |
| 7 | +order: "1.6.1" |
| 8 | +--- |
| 9 | +*JsonSchema.Net.CodeGeneration* is a tool that can create C# code from JSON Schemas. |
| 10 | + |
| 11 | +For example, given the schema: |
| 12 | + |
| 13 | +```json |
| 14 | +{ |
| 15 | + "title": "MyObject", |
| 16 | + "type": "object", |
| 17 | + "properties": { |
| 18 | + "Foo": { "type": "string" } |
| 19 | + } |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +it can generate a C# class like |
| 24 | + |
| 25 | +```c# |
| 26 | +public class MyObject |
| 27 | +{ |
| 28 | + public string Foo { get; set; } |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +## Capabilities {#schema-codegen-capabilities} |
| 33 | + |
| 34 | +The code generation is currently quite basic. It will generate types for simple custom objects and any named array or dictionary type. |
| 35 | + |
| 36 | +`$ref` is generally supported, even for recursive models like linked lists and binary trees, however there is no loop detection, so if you do something like this: |
| 37 | + |
| 38 | +```json |
| 39 | +{ |
| 40 | + "$ref": "#" |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +you'll just get a stack overflow exception. That's on you. Don't do that. |
| 45 | + |
| 46 | +### Built-in types |
| 47 | + |
| 48 | +Built-in types, like strings and arrays, are supported by reference only. These generally will not have type declarations generated for them, however they can appear as types used within other declarations. For example, `string` in the example above is used for the `Foo` property, but there isn't a `string` type declaration included in the output because the type is built-in. |
| 49 | + |
| 50 | +There is an exception to this behavior for arrays and dictionaries, which is explained [below](#including-a-name). |
| 51 | + |
| 52 | +## Usage |
| 53 | + |
| 54 | +There is currently limited support for translating JSON Schema into code. However there is ongoing discussion for an official [JSON Schema code generation vocabulary](https://github.com/json-schema-org/vocab-idl). Please feel free to read up and join in on the effort there. |
| 55 | + |
| 56 | +Currently, the class name is derived from the `title` keyword. There is an open issue in the repository above to discuss using this keyword. It's currently leaning toward the vocabulary defining a custom keyword, but as nothing has been decided yet, `title` is used here for now. |
| 57 | + |
| 58 | +### Custom objects |
| 59 | + |
| 60 | +Generating for custom objects is the real power behind code generation. Being able to read a schema produced by some other developer (e.g. from an OpenAPI document) and automatically create types can save developers a lot of time. |
| 61 | + |
| 62 | +This library generates custom types for schemas that declare an `object` type and include `title` and `properties` without `additionalProperties`. It will also automatically generate types found nested in the schema. For example |
| 63 | + |
| 64 | +```json |
| 65 | +{ |
| 66 | + "title": "MyCustomObject", |
| 67 | + "type": "object", |
| 68 | + "properties": { |
| 69 | + "Foo": { "type": "string" }, |
| 70 | + "Bar": { |
| 71 | + "title": "Bar", |
| 72 | + "type": "object", |
| 73 | + "properties": { |
| 74 | + "Baz": { "type": "integer" } |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +generates |
| 82 | + |
| 83 | +```c# |
| 84 | +public class MyCustomObject |
| 85 | +{ |
| 86 | + public string Foo { get; set; } |
| 87 | + public Bar Bar { get; set; } |
| 88 | +} |
| 89 | + |
| 90 | +public class Bar |
| 91 | +{ |
| 92 | + public int Baz { get; set; } |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +There is some basic duplicate definition detection that serves two purposes: |
| 97 | + |
| 98 | +1. It avoids creating multiple declarations for the same type. For example, if `Foo` had `Bar1` and `Bar2` properties, only one `Bar` declaration would be generated. Ideally this kind of duplication should be defined in the schema using a `$ref`. |
| 99 | +2. It prevents creating multiple types with the same name. For example, if there are two subschemas with the same name that define two different types, an exception would be thrown indicating the name re-use. |
| 100 | + |
| 101 | +For type and property naming, some basic string transformation occurs: |
| 102 | + |
| 103 | +| Original | Transformed | |
| 104 | +|:-|:-| |
| 105 | +| `kebab-case` | `KebabCase` | |
| 106 | +| `snake_case` | `SnakeCase` | |
| 107 | +| `spaced words` |`SpacedWords` | |
| 108 | +| `words-with-2-numbers` | `WordsWith2Numbers` | |
| 109 | +| `just-a-letter` | `JustALetter` | |
| 110 | + |
| 111 | +Anything other conventions will likely result in undesirable code output or an exception. |
| 112 | + |
| 113 | +### Arrays |
| 114 | + |
| 115 | +When a schema declares an `array` type and includes an `items` keyword (in the single schema form, not an array of schemas), an array is used. |
| 116 | + |
| 117 | +```json |
| 118 | +{ |
| 119 | + "type": "array", |
| 120 | + "items": { |
| 121 | + "type": "integer" |
| 122 | + } |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +produces no declaration, but using this schema (e.g. to define object properties) appears as |
| 127 | + |
| 128 | +```c# |
| 129 | +int[] |
| 130 | +``` |
| 131 | + |
| 132 | +### Dictionaries |
| 133 | + |
| 134 | +When a schema declares an `object` type and only includes `additionalProperties` without `properties`, this models a dictionary. |
| 135 | + |
| 136 | +```json |
| 137 | +{ |
| 138 | + "title": "MyIntDictionary", |
| 139 | + "type": "object", |
| 140 | + "additionalProperties": { |
| 141 | + "type": "integer" |
| 142 | + } |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +This also produces no declaration, but using the schema appears as |
| 147 | + |
| 148 | +```c# |
| 149 | +Dictionary<string, int> |
| 150 | +``` |
| 151 | + |
| 152 | +### Including a name on basic types {#including-a-name} |
| 153 | + |
| 154 | +When you have an array or dictionary schema with a `title` keyword |
| 155 | + |
| 156 | +```json |
| 157 | +{ |
| 158 | + "title": "MyIntArray", |
| 159 | + "type": "array", |
| 160 | + "items": { |
| 161 | + "type": "integer" |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +or |
| 167 | + |
| 168 | +```json |
| 169 | +{ |
| 170 | + "title": "MyIntDictionary", |
| 171 | + "type": "object", |
| 172 | + "additionalProperties": { |
| 173 | + "type": "integer" |
| 174 | + } |
| 175 | +} |
| 176 | +``` |
| 177 | + |
| 178 | +you now get a type declaration inheriting from `List<T>` |
| 179 | + |
| 180 | +```c# |
| 181 | +public class MyIntArray : List<int> {} |
| 182 | +``` |
| 183 | + |
| 184 | +and `Dictionary<TKey, TValue>` |
| 185 | + |
| 186 | +```c# |
| 187 | +public class MyIntDictionary : Dictionary<string, int> {} |
| 188 | +``` |
| 189 | + |
| 190 | +and usages will correctly appear as `MyIntArray` and `MyIntDictionary`, respectively. |
| 191 | + |
| 192 | +Other basic types (e.g. strings) will ignore the `title` keyword as these types cannot be inherited. |
0 commit comments