JSON Type Definition, aka RFC8927, is an easy-to-learn, standardized way to define a schema for JSON data. You can use JSON Typedef to portably validate data across programming languages, create dummy data, generate code, and more.
Jetted is a fork of the original jtd-codegen project,
which has not seen any updates since 2021, and appears to be abandoned. The project was
forked at commit a42555d,
at which point the project was MIT-licensed. We intend to continue development of Jetted
under the MIT license.
We'd like to thank the original authors of jtd-codegen for their work on this project.
- Added additional traits to generated Rust types to support cloning, equivalence, ordering, etc.
- Changed field names to be snake_case instead of camelCase.
jetted is a CLI tool that generates code bindings in many different
programming languages from JSON Typedef schemas. For example, from this JSON
Typedef schema:
{
"properties": {
"name": { "type": "string" },
"isAdmin": { "type": "boolean" },
"favoriteNumbers": { "elements": { "type": "float64" }}
}
}You can generate this TypeScript interface:
export interface User {
favoriteNumbers: number[];
isAdmin: boolean;
name: string;
}Or this Go type:
package user
type User struct {
FavoriteNumbers []float64 `json:"favoriteNumbers"`
IsAdmin bool `json:"isAdmin"`
Name string `json:"name"`
}Or types/classes/structs for any of the following programming languages:
- C# with
System.Text.Jsonas the JSON backend - Golang
- Java with Jackson as the JSON backend
- Python
- Rust
- TypeScript
With many more on the way. If you'd like a particular programming language included, please open an issue on this repo!
JSON Type Definition is a schema format for JSON data. A JSON Type Definition schema describes what is and isn't a "valid" JSON document. JSON Type Definition is easy to learn, portable (there are functionally-identical implementations across many programming languages) and standardized (the spec is set in stone as IETF RFC 8927).
Here's an example of a JSON Type Definition schema:
{
"properties": {
"name": {
"type": "string"
},
"isAdmin": {
"type": "boolean"
}
}
}This schema considers any object with a name property (whose value must be a
string), an isAdmin property (whose value must a boolean), and no other
properties, to be valid.
To learn more about JSON Type Definition, check out the online documentation at jsontypedef.com.
Go to the latest jetted release on
GitHub,
and then install the file for your platform.
To use jetted, you first need to have a JSON Typedef schema to generate
data from. Let's say you have this example data already in place:
$ cat user.jtd.json
{
"properties": {
"name": { "type": "string" },
"isAdmin": { "type": "boolean" },
"favoriteNumbers": { "elements": { "type": "float64" }}
}
}
Then you can invoke jetted as:
# make sure you've already created the "user" directory before running this
$ jetted user.jtd.json --typescript-out user
π Writing TypeScript code to: user
π¦ Generated TypeScript code.
π¦ Root schema converted into type: UserIn that example, we generated TypeScript code. If you want to generate something else, use the appropriate "out" parameter for your desired language. For specific instructions for each programming languages, check out the documentation for:
- C# with
System.Text.Jsonas the JSON backend - Golang
- Java with Jackson as the JSON backend
- Python
- TypeScript
You can produce code for multiple programming languages at once. Just pass all
of the relevant parameters in the jetted invocation. For example:
$ jetted user.jtd.json --typescript-out ts-user --python-out py-user
π Writing Python code to: py-user
π¦ Generated Python code.
π¦ Root schema converted into type: User
π Writing TypeScript code to: ts-user
π¦ Generated TypeScript code.
π¦ Root schema converted into type: User
If you'd like to add a commented description to generated code -- for example,
JavaDocs for Java code, or a docstring for Python -- jetted supports
those via the description and enumDescription fields in any schema's
metadata.
For example, this schema:
{
"properties": {
"name": {
"metadata": {
"description": "The user's name"
},
"type": "string"
},
"status": {
"metadata": {
"description": "The user's account status",
"enumDescription": {
"UNVERIFIED": "The user's email has not yet been verified",
"VERIFIED": "The user's email has been verified",
"DISABLED": "The user's account was terminated"
}
},
"enum": ["UNVERIFIED", "VERIFIED", "DISABLED"]
}
}
}Generates into this TypeScript:
/**
* The user's account status
*/
export type UserStatus =
/**
* The user's account was terminated
*/
| "DISABLED"
/**
* The user's email has not yet been verified
*/
| "UNVERIFIED"
/**
* The user's email has been verified
*/
| "VERIFIED"
export interface User {
/**
* The user's name
*/
name: string;
/**
* The user's account status
*/
status: UserStatus;
}If you'd like to force jetted to use a particular type/class for some
subset of your schema, you can use a "type override" property to do this. For
example, if you generate TypeScript from this schema:
{
"properties": {
"name": {
"metadata": {
"typescriptType": "MyCustomNameType"
},
"type": "string"
},
"isAdmin": { "type": "boolean" },
"favoriteNumbers": { "elements": { "type": "float64" }}
}
}You'll get:
export interface User {
favoriteNumbers: number[];
isAdmin: boolean;
name: MyCustomNameType;
}Each language supported by jetted supports a different set of overrides:
- C# with
System.Text.Jsonas the JSON backendcsharpSystemTextTypeoverrides the entire outputted typecsharpSystemTextContaineroverridesIList<T>orIDictionary<string, T>in favor of a different container type
- Golang
goTypeoverrides the entire outputted type
- Java with Jackson as the JSON backend
javaJacksonTypeoverrides the entire outputted typejavaJacksonContaineroverridesList<T>orMap<String, T>in favor of a different container type
- Python
pythonTypeoverrides the entire outputted type
- Rust
rustTypeoverrides the entire outputted type
- TypeScript
typescriptTypeoverrides the entire outputted type
If you're using jetted as part of a larger build process (for example: if
you're building an OpenAPI-like format on top of JSON Typedef), you may find it
useful to programmatically get back the names of jetted-generated types.
jetted supports this use-case via the --log-format CLI option.
By default, jetted uses --log-format pretty, which outputs
human-friendly text to stdout. This is an example of pretty output:
π Writing TypeScript code to: user
π¦ Generated TypeScript code.
π¦ Root schema converted into type: User
π¦ Definition "name" converted into type: Name
If instead you use --log-format minimal, then jetted outputs startup
diagnostic information to stderr, and information about generated data
structures to stdout:
TypeScript: writing to: user
TypeScript: root: User
TypeScript: definition: name: Name
(The first line above is to stderr, the subsequent two lines are to stdout.)
Finally, --log-format json outputs information about generated data structures
to stdout as JSON. No startup information is produced:
{
"TypeScript": {
"out_dir": "user",
"root_name": "User",
"definition_names": {
"name": "Name"
}
}
}Typically speaking, --log-format minimal is easier to process in simple bash
scripts. --log-format json is often easier to use from anything that's not a
shell-like programming language.