Crate magnet_schema [] [src]

Magnet, a JSON/BSON schema generator

These two related crates, magnet_schema and magnet_derive define a trait, BsonSchema, and a proc-macro derive for the same trait, which allows types to easily implement JSON schema validation for use with MongoDB.

The trait defines a single function, bson_schema(), that returns a BSON Document describing the validation schema of the type based on its fields (for structs and tuples), variants (for enums), or elements/entries (for array- and map-like types).

The types are expected to be serialized and deserialized using Serde, and generally Magnet will try very hard to respect #[serde(...)] annotations as faithfully as possible, but no Serialize + Deserialize trait bounds are enforced on the types as this is not strictly necessary.

Usage Example

#[macro_use]
extern crate bson;
#[macro_use]
extern crate magnet_derive;
extern crate magnet_schema;

use std::collections::HashSet;
use magnet_schema::BsonSchema;

#[derive(BsonSchema)]
struct Contact {
    name: String,
    nicknames: HashSet<String>,
    age: usize,
    email: Option<String>,
}

fn main() {
    let schema_doc = Contact::bson_schema();
    println!("{:#?}", schema_doc);
}

Custom Attributes

  • #[magnet(rename = "new_name")]: applied to a struct field or an enum variant, it will rename it to the provided new name when generating the JSON schema. This attribute overrides #[serde(rename = "...")] (in the generated JSON schema only!) if it is present on the same field.

  • #[serde(rename = "new_name")]: Magnet will respect Serde's field/variant renaming attribute by default, if Magnet's own rename is not present.

  • #[serde(rename_all = "rename_rule")]: it will also respect Serde's rename_all rule if Magnet's own rename attribute is not specified.

Development Roadmap

  • [x] Define BsonSchema trait

  • [x] impl BsonSchema for most primitives/std:: types

  • [x] Cargo features for implementing BsonSchema for "atomic" types in foreign crates, for instance, url::Url and uuid::Uuid.

  • [x] #[derive(BsonSchema)] on regular, named-field structs

  • [x] #[derive(BsonSchema)] on newtype structs

  • [x] #[derive(BsonSchema)] on tuple structs

  • [x] #[derive(BsonSchema)] on unit structs

  • [ ] #[derive(BsonSchema)] on enums

    • [ ] unit variants

    • [ ] newtype variants

    • [ ] tuple variants

    • [ ] struct variants

    • [ ] respect Serde tagging conventions: external/internal/adjacent

  • [x] Respect more #[serde(...)] attributes, for example: rename, rename_all

  • [ ] Respect more #[serde(...)] attributes, for example: default, skip, skip_serializing, skip_deserializing

  • [ ] Handle generic types in proc-macro derive

  • [ ] Standard (non-MongoDB-specific) JSON schema support (approach?)

  • [ ] UNIT TESTS!!!

  • [ ] DOCUMENTATION FOR ATTRIBUTES!!!

  • [ ] impl BsonSchema for more esoteric primitives/standard types such as specialization of [u8]/Vec<u8> as binary, adding a validation regex "pattern" to Path and PathBuf, etc.

  • [ ] Add our own attributes

    • [x] magnet(rename = "...") — renames the field or variant to the name specified as the value of the rename attribute

    • [ ] magnet(regex = "foo?|[ba]r{3,6}") — custom validation; implies "type": "string". Patterns are implicitly enclosed between ^...$ for robustness.

    • [ ] magnet(unsafe_regex = "^nasty-regex$") — just like magnet(regex), but no automatic enclosing in ^...$ happens. This may allow invalid data to pass validation!!!

    • [ ] magnet(non_empty) — for collections: same as min_length = "1".

    • [ ] magnet(min_length = "16") — for collections/tuples etc.

    • [ ] magnet(max_length = "32") — for collections/tuples etc.

    • [ ] magnet(incl_min = "-1337") — inclusive minimum for numbers

    • [ ] magnet(excl_min = "42") — exclusive "minimum" (infimum) for numbers

    • [ ] magnet(incl_max = "63") — inclusive maximum for numbers

    • [ ] magnet(excl_max = "64") — exclusive "maximum" (supremum) for numbers

    • [ ] magnet(allow_extra_fields) — sets "additionalProperties": true. By default, Magnet sets this field to false for maximal safety. Allowing arbitrary data to be inserted in a DB is generally a Bad Idea, as it may lead to code injection (MongoDB supports storing JavaScript in a collection! Madness!) or at best, denial-of-service (DoS) attacks.

    • [ ] magnet(allow_extra_fields = "ExtraFieldType") — sets "additionalProperties": ExtraFieldType::bson_schema(), so that unlisted additional object fields are allowed provided that they conform to the schema of the specified type.

Traits

BsonSchema

Types which can be expressed/validated by a MongoDB-flavored JSON schema.