magnet icon indicating copy to clipboard operation
magnet copied to clipboard

Json schema

Open xoac opened this issue 7 years ago • 8 comments

Hi, You described crate as JSON/BSON schema generator. But for now there is no Json schema generator (or I can't find)? Do you have plan to add it?

For example: Generate from rust struct used bson_schema().

{
  "type": "object",
  "additionalProperties": false,
  "required": [
    "i"
  ],
  "properties": {
    "i": {
      "bsonType": [
        "int",
        "long"
      ],
      "minimum": -2147483648,
      "maximum": 2147483647
    }
  }
}

for json should looks like this:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "i": {
      "type": "integer",
      "minimum": -2147483648, 
      "maximum": 2147483647
    }
  },
  "required": [
    "i"
  ]
}

I am not using it with mongo, so question is that u want to make it more general?

xoac avatar Aug 21 '18 08:08 xoac

Hi, and thanks for contributing!

Yes, generation of regular standard-conformant JSON schemas is also planned, it's just that I needed this for MongoDB validation so that was the first thing I implemented. The code needs some refactoring anyway, because the way it handles some features (e.g. enum tagging and maximum/minimum bounds) got a bit convoluted, but after that, two additional things should be possible: – JSON schema generation and – adding comment fields based on doc comments for human consumers of the schemas (there's an outstanding partial pull request for it already).

H2CO3 avatar Aug 21 '18 10:08 H2CO3

Great. I need JSON schema to my project. I am new to rust macros. But if u have some plan how to refactor and describe how would u like API should be. I can try submit PR.

Are u plan to support just draft4 or draft7 also?

xoac avatar Aug 22 '18 08:08 xoac

I think if we adhere to a standard it might as well be the latest one, so I'd say let's target v7 unless there's something in it that's excessively difficult to implement (I haven't yet looked at the differences, will do during the weekend.)

H2CO3 avatar Aug 23 '18 12:08 H2CO3

Feel free to notify me with your plan of impl/refactor. I am rather junior but I will try help if you wish.

xoac avatar Aug 24 '18 19:08 xoac

Hi guys,

Any update on your plan regarding this json schema generator? I may be able to contribute, also, I expect also some convergence with serde json. Perhaps you already have some good view on the next steps to get a good json schema generator

jo2wan avatar Dec 02 '18 07:12 jo2wan

Hey there! Unfortunately, these days I have very little time to add new features. 😞 Implementing this without excessive code copy-and-paste would require at least some sort of refactoring. Anyone is welcome to start that, so if you're interested, let me explain it in more detail.

H2CO3 avatar Dec 03 '18 07:12 H2CO3

Yes, sure, please share your plan for refactoring/impl. I'll see how I can contribute.

jo2wan avatar Dec 03 '18 08:12 jo2wan

Awesome! So, here are a couple of things – this list is possibly (likely) non-exhaustive, so I'll have to trust you with good taste and style:

  • The magnet_schema crate:

    • Add the serde_json dependency to Cargo.toml and the extern crate declaration to lib.rs

    • Add the definition of the JsonSchema trait, based on BsonSchema, like this:

      use serde_json::Value;
      
      /// Types which can be expressed/validated by a standard v7 JSON schema.
      pub trait JsonSchema {
          /// Returns a JSON value describing the JSON schema of this type.
          fn json_schema() -> Value;
      }
      
    • Implement JsonSchema for the relevant primitive and std:: types, based on the JSON schema v7 spec and following the examples of impl BsonSchema for the same types in the crate.

    • support.rs needs some more love too, you'll probably need to implement the already-existing functions for serde_json::Value too. I don't know how similar they will be to the existing ones (arising out of necessity), but if they do turn out to be very similar, you should probably think about changing the functions over concrete types into generics, and indirectly using a trait instead, implemented by both bson::Document and serde_json::Value, for extending and modifying JSON/BSON schema contents.

  • The magnet_derive crate:

    • Add the derive proc-macro for the JsonSchema trait It will probably look like:
      #[proc_macro_derive(JsonSchema, attributes(magnet))]
      pub fn derive_json_schema(input: TokenStream) -> TokenStream {
          …
      }
      
    • Add its actual implementation, like:
      // Implements `JsonSchema` for a given type based on its
      /// recursively contained types in fields or variants.
      fn impl_json_schema(input: TokenStream) -> Result<TokenStream> {
          …
      }
      
    • Generalize AST generator functions. The modus operandi of generalization should probably be the following:
      • Add an enum SchemaKind { Bson, Json }
      • Add a new argument to the functions in question: kind: SchemaKind
      • When generating code that refers to bson::{ Bson, Document } or serde_json::Value or (perhaps even more importantly) the actual content of the resulting schema document (e.g. map keys, type names, etc…) switch on this schema kind argument to decide which one to generate.
      • Thinking about it, the approach in the previous bulletpoint can become messy. I could imagine this being implemented by various methods on SchemaKind instead, so the differences (and the data) are grouped together in a central location, and not dispersed around the entire code base, making it more data-oriented and less ad-hoc.
      • These AST generator functions reside in the following modules:
        • generics.rs (with_bson_schema() and the like should probably be renamed with_schema(kind: SchemaKind))
        • error.rs (just need to add JsonSchema in two doc comments)
        • codegen_enum.rs, codegen_field.rs, codegen_struct.rs, and codegen_union.rs

Thanks for picking this up, and good luck!

H2CO3 avatar Dec 03 '18 10:12 H2CO3