Typify compiles JSON Schema documents into Rust types. It can be used in one of three ways:
-
via the macro
import_types!("types.json")
to generate Rust types directly in your program -
via a builder interface to generate Rust types in
build.rs
-
or via the builder functions to generate persistent files e.g. when building API bindings.
Typify translates JSON Schema types in a few different ways depending on some basic properties of the schema:
Integers, floating-point numbers, strings, etc. Those all have straightforward representations in Rust. The only significant nuance is how to select the appropriate built-in type based on type attributes. For example, a JSON Schema might specify a maximum and/or minimum that indicates the appropriate integral type to use.
String schemas that include a format
are represented with the appropriate
Rust type. For example { "type": "string", "format": "uuid" }
is represented
as a uuid::Uuid
(which requires the uuid
crate be included as a dependency).
JSON Schema arrays can turn into one of three Rust types Vec<T>
,
HashSet<T>
, and tuples depending on the schema properties. An array may have
a fixed length that matches a fixed list of item types; this is well
represented by a Rust tuples. The distintion between Vec<T>
and HashSet<T>
is only if the schema's uniqueItems
field is false
or true
respectively.
In general, objects turn in to Rust structs. If, however, the schema defines no
properties, Typify emits a HashMap<String, T>
if the additionalProperties
schema specifies T
or a HashMap<String, serde_json::Value>
otherwise.
Properties that are not in the required
set ar typically represented as an
Option<T>
with the #[serde(default)]
attribute applied. Non-required
properties with types that already have a default value (such as a Vec<T>
)
simply get the #[serde(default)]
attribute (so you won't see e.g.
Option<Vec<T>>
).
The OneOf
construct maps to a Rust enum. Typify maps this to the various serde enum types.
The anyOf
and allOf
constructs are a little trickier to handle, but (in
general) Typify models these as structs where each member is decorated with the
#[serde(flatten)]
attribute (with Option
wrappers in the case of anyOf
).
Typify is a work in progress. Changes that affect output will be indicated with a breaking change to the crate version number.
In general, if you have a JSON Schema that causes Typify to fail or if the generated type isn't what you expect, please file an issue.
There are some known areas where we'd like to improve:
A useful addition would be to have Typify (builder or macro) accept a map of JSON Schemas to named Rust types. This would allow consumers to substitute a preferred type for some known schema.
A string schema with format
set to uuid
will result in the uuid::Uuid
type; similarly, a format
of date
translates to
chrono::Date<chrono::offset::Utc>
. For users that don't want dependencies on
uuid
or chrono
it would be useful for Typify to optionally represent those
as String
(or as some other, consumer-specified type).
Typify has special-case handling for self-referential types. For example:
struct A {
a: Box<A>,
}
.. but it does not support more complex cycles such as A -> B -> A.