gresau / schemars Goto Github PK
View Code? Open in Web Editor NEWGenerate JSON Schema documents from Rust code
Home Page: https://graham.cool/schemars/
License: MIT License
Generate JSON Schema documents from Rust code
Home Page: https://graham.cool/schemars/
License: MIT License
$ref
(make SchemaGenerator::make_extensible()
a no-op)Hello again, sorry for cluttering your inbox with GitHub issues.
I've just taken a quick look so far, but I see that the source code for Schemars support validations like pattern
for strings (https://github.com/GREsau/schemars/blob/master/schemars/src/schema.rs#L364). Is there any way of adding validations to a schema? I couldn't find any information on the site about this, so that's why I'm asking.
Minimal repro:
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(default)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
}
Output when running cargo clippy
with Rust 1.48:
work1pass@jareks-mbp-work schemars-test % cargo clippy
Compiling proc-macro2 v1.0.24
Compiling unicode-xid v0.2.1
Compiling syn v1.0.56
Compiling serde_derive v1.0.118
Compiling ryu v1.0.5
Compiling serde v1.0.118
Compiling serde_json v1.0.61
Compiling schemars v0.8.0
Checking itoa v0.4.7
Checking dyn-clone v1.0.4
Compiling quote v1.0.8
Compiling serde_derive_internals v0.25.0
Compiling schemars_derive v0.8.0
Checking schemars-test v0.1.0 (/Users/work1pass/programming/schemars-test)
Finished dev [unoptimized + debuginfo] target(s) in 17.08s
Output when running cargo clippy
with Rust 1.49:
work1pass@jareks-mbp-work schemars-test % cargo clippy
Compiling proc-macro2 v1.0.24
Compiling unicode-xid v0.2.1
Compiling syn v1.0.56
Compiling serde_derive v1.0.118
Compiling ryu v1.0.5
Compiling serde v1.0.118
Compiling serde_json v1.0.61
Checking itoa v0.4.7
Compiling schemars v0.8.0
Checking dyn-clone v1.0.4
Compiling quote v1.0.8
Compiling serde_derive_internals v0.25.0
Compiling schemars_derive v0.8.0
Checking schemars-test v0.1.0 (/Users/work1pass/programming/schemars-test)
warning: field assignment outside of initializer for an instance created with Default::default()
--> src/lib.rs:3:57
|
3 | #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
| ^^^^^^^^^^
|
= note: `#[warn(clippy::field_reassign_with_default)]` on by default
note: consider initializing the variable with `schemars::schema::Metadata { default: JsonSchema, ..Default::default() }` and removing relevant reassignments
--> src/lib.rs:3:57
|
3 | #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
| ^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: field assignment outside of initializer for an instance created with Default::default()
--> src/lib.rs:3:57
|
3 | #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
| ^^^^^^^^^^
|
note: consider initializing the variable with `schemars::schema::Metadata { default: JsonSchema, ..Default::default() }` and removing relevant reassignments
--> src/lib.rs:3:57
|
3 | #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
| ^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 2 warnings emitted
Finished dev [unoptimized + debuginfo] target(s) in 16.39s
Hi! This project looks very promising for generating auto documentation for Rocket web servers. I'd like to integrate this into my application, but to do that I need a couple of derivations of JsonSchema that currently don't exists. Mainly, the chrono
types for datetimes and tuple structs. Is this something that is on the roadmap, or that you might be able to help me implement myself?
Hey I'm trying to generate typescript types from the generated JSON schema and am running into a bit of a design constraint.
Basically the generated type for an enum that has [#serde(tag="...")]
gets turned into an anyOf
where the resulting types are directly mentioned without them being given a definition. This is in contrast from for instance using [#serde(tag="t", content="c")]
where a new definition is inserted for every type of content.
When generating Typescript the latter is much more convenient since you get a discriminated union where you can still refer to each individual item since they will be named. In contrast the former just gives a giant union blob where it's hard to do things like casting to a specific type.
I would like to figure out a way we can make the JSON schema more verbose and essentially generate definitions for every enum item. Happy to make a PR if someone can point me in the right direction of where to find the relevant code bits.
Thanks for this great project. At CosmWasm/cosmwasm#168 we are planning the upgrade to 0.6 or 0.7, but a bit unsure which code branch to use. Is anything missing for a 0.7.0 freeze? Apha versions are online for a couple of months now.
Cheers
The current implementation for impl JsonSchema for Value
where Value is serde_json::Value does not work well.
https://github.com/GREsau/schemars/blob/master/schemars/src/json_schema_impls/serdejson.rs
Because this is a very special type it might be tricky.
Currently when this value is included in a response it will not set a type.
When a description is given it will set that. But that is about it.
The 'value' variable is the serde_json::Value type in the screenshot below.
Because of this UI's have a hard time parsing this.
RapiDoc: (an okay response)
Swagger UI: (Does not even acknowledge it, but in schema it is better)
I know these are issues with UI's and not Schemars. And the Spec does not really give any option for this.
But maybe we can use "allOf", "oneOf", "anyOf" to allow all types ("integer", "number", "string" and "boolean"). This will make sure there is at least something good there.
I noticed spurious SubschemaValidation.all_of
s with a single element being included. For example:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "B",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"description": "doc comment",
"allOf": [
{
"$ref": "#/definitions/Name"
}
]
}
},
"definitions": {
"Name": {
"type": "string"
}
}
}
I was able to narrow this down to a simple test case where the presence of a doc comment seems to trigger the behavior:
use schemars::schema_for;
use schemars::JsonSchema;
#[derive(JsonSchema)]
pub struct Name(String);
#[derive(JsonSchema)]
pub struct A {
/** doc comment */
pub name: Name,
}
#[derive(JsonSchema)]
pub struct B {
/// doc comment
pub name: Name,
}
#[derive(JsonSchema)]
pub struct C {
// non-doc comment
pub name: Name,
}
fn main() {
let schema = schema_for!(A);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
let schema = schema_for!(B);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
let schema = schema_for!(C);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}
... which outputs:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"description": "doc comment",
"allOf": [
{
"$ref": "#/definitions/Name"
}
]
}
},
"definitions": {
"Name": {
"type": "string"
}
}
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "B",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"description": "doc comment",
"allOf": [
{
"$ref": "#/definitions/Name"
}
]
}
},
"definitions": {
"Name": {
"type": "string"
}
}
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "C",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"$ref": "#/definitions/Name"
}
},
"definitions": {
"Name": {
"type": "string"
}
}
}
Note that the C
does not contain the allOf
clause (and has no doc-comment).
I was able to reproduce this on 0.7.6 and 0.8.0-alpha-2.
I'm happy to fix this myself if you'd accept the PR.
Seems like enums never set additionalProperties
even if if you denied them using #[schemars(deny_unknown_fields)]
or #[serde(deny_unknown_fields)]
.
My enum:
#[derive(Deserialize, Serialize, JsonSchema)]
///Every event that the game sends to the editor
#[serde(deny_unknown_fields)]
pub enum SendEvents {
EditRectangle(AddRectangle),
EditImage(ImageParams)
}
the repo where this happens: https://github.com/lenscas/silver_editor/tree/feature/more_forms (the json schema's are generated by a buildscript in /editor
, the types that are being used to generate the schema are in /event_types/src/events.rs
I wouldn't mind opening a pull request myself to fix this, however I haven't really made macro's before so not sure if I can fix it myself :(
Either way, thank you for making this crate. It allows me to generate typescript types with ease and simplifying a large chunk from my current project because of it!
In case of an exported Rust type, the generated schema does not respect its name.
For example:
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct MyObject<D> {
pub data: D,
}
pub type MyObjectType = MyObject<String>;
fn main() {
let alias_schema = schema_for!(MyObjectType);
println!("schema: \n{:?}", serde_json::to_string_pretty(&alias_schema).unwrap());
}
In this example, the object's name in the schema is MyObject_for_String
, would it be possible instead to use MyObjectType
as name?
Nevertheless, I am not sure if this can be achieved in Rust.
https://serde.rs/container-attrs.html#transparent
Serialize and deserialize a newtype struct or a braced struct with one field exactly the same as if its one field were serialized and deserialized by itself. Analogous to #[repr(transparent)].
The clap and structopt crates use the rustdoc comment for describing cli arguments.
I think the same approach can be used to fill jsonschemas title and description fields.
One way of interpreting those is, to use the rustdoc comment for description
, expect if the first line starts with a markdown heading character ("#") which would be used for the title
instead. Example:
struct foo {
/// # The title
/// The description text
an_int: u16
};
WDYT?
First of all, awesome library! I was dabbling with writing something similar and was very happy that this library exists!
I ran into an issue when trying to generate a schema for a tagged enum. See reproducer below.
use serde::{Serialize, Deserialize};
use schemars::{JsonSchema, schema_for};
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct BValues {
a: u32,
b: u32,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type")]
pub enum Foo {
#[serde(rename = "a")]
A,
#[serde(rename = "b")]
B(BValues),
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let schema = schema_for!(Foo)?;
println!("{}", serde_json::to_string_pretty(&schema)?); // fails
Ok(())
}
This produces the following error:
Error: JsonSchemaError { msg: "Only schemas with type `object` can be flattened.", schema: Ref(Ref { reference: "#/definitions/BValues" }) }
is there any support for examples
annotation entries available in schemars and how to realize this kind of augmentation with serde resp. docstrings or anything similar?
unfortunately i couldn't find anything about this kind of non-validation oriented auxiliary annotations in the present schemars documentation and examples.
I was curious about the stability guarantees that schemars
provides, referencing this thread: rustgd/cgmath#516 (comment)
Specifically:
Would it work if the struct has fields serialized by different versions of this crate?
Hi
before run test i added in schemars/Cargo.toml
[dev-dependencies]
chrono = { version = "0.4" }
and removed
[[test]]
name = "chrono"
required-features = ["chrono"]
run (my OS Debian GNU/Linux 10)
cargo test chrono
result
schemars/tests/chrono.rs:9:5
|
9 | date_time: DateTime,
| ^^^^^^^^^ function or associated item not found in chrono::datetime::DateTime<chrono::offset::utc::Utc>
|
= note: the method add_schema_as_property
exists but the following trait bounds were not satisfied:
&chrono::datetime::DateTime<chrono::offset::utc::Utc> : schemars::JsonSchema
&mut chrono::datetime::DateTime<chrono::offset::utc::Utc> : schemars::JsonSchema
Consider the below code:
#[macro_use]
extern crate validator_derive;
extern crate validator;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use schemars::{schema_for, JsonSchema};
#[derive(Debug, Validate, Deserialize, Default, JsonSchema)]
#[serde(default)]
struct Preference {
/// `name` must be at least 4 characters long
#[validate(length(min = 4))]
name: String,
value: bool,
}
The above would mark name
as not required, but due to the validate step, it is.
In order for the validator to work, the Deserialization must happen first, hence the container level #[serde(default)]
.
I would like a property level attribute to be able to hint to schemars, that a field, despite #[serde(default)]
is in fact required.
Unless marking fields required is already possible somehow with schemars.
Trying to serialize a struct like this
pub enum Example {
#[serde(serialize_with = "serialize_function")]
Function(String, functions::QueryFn),
}
I get
error[E0277]: the trait bound `for<'r, 's, 't0> fn(std::vec::Vec<datatype::DataType>, &'r std::collections::HashMap<&'s str, datatype::DataType>, &'t0 aw_datastore::worker::Datastore) -> std::result::Result<datatype::DataType, QueryError>: schemars::JsonSchema` is not satisfied
--> aw-query/src/datatype.rs:18:27
|
18 | #[derive(Clone,Serialize, JsonSchema)]
| ^^^^^^^^^^ the trait `schemars::JsonSchema` is not implemented for `for<'r, 's, 't0> fn(std::vec::Vec<datatype::DataType>, &'r std::collections::HashMap<&'s str, datatype::DataType>, &'t0 aw_datastore::worker::Datastore) -> std::result::Result<datatype::DataType, QueryError>`
|
= note: required because of the requirements on the impl of `schemars::JsonSchema` for `(std::string::String, for<'r, 's, 't0> fn(std::vec::Vec<datatype::DataType>, &'r std::collections::HashMap<&'s str, datatype::DataType>, &'t0 aw_datastore::worker::Datastore) -> std::result::Result<datatype::DataType, QueryError>)`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
I was very pleased to see that schemars already includes code comments in the generated schemas. I mainly use schemars to improve the IDE experience, so this is really great.
This feature comes with a basic Markdown parsing feature: it removes single carriage returns (link to the code: https://github.com/GREsau/schemars/blob/master/schemars_derive/src/attr/doc.rs)
In the project I'm currently working on, the comments use more features of Markdown, including lists, code blocks and link references. These currently do not translate well to text.
As an example, here's a comment: https://github.com/fbecart/zinoma/blob/cc38f93734f0a8d79e12f8b5228fecb178bc68fe/src/config/yaml/schema.rs#L64-L90
This renders as the following JSON schema:
"targets": {
"description": "A build flow is made of [`targets`]. Each target is a unit of work to perform as part of this build flow.\n\n[`targets`]: struct.Target.html\n\nTargets run in parallel by default. To run targets sequentially, you can define dependencies on other targets using the [`dependencies`] keyword.\n\n[`dependencies`]: struct.Target.html#structfield.dependencies\n\nEach target must have a unique name. The target name must be a string. It should start with an alphanumeric character or `_` and contain only alphanumeric characters, `-`, or `_`.\n\n__Example__\n\n```yaml targets: speak_cow: build: echo 'Moo' speak_dog: build: echo 'Woof!' ```\n\nIn this example:\n\n- `zinoma speak_cow` will print `Moo` - `zinoma speak_dog` will print `Woof!` - `zinoma speak_cow speak_dog` will print both `Moo` and `Woof!`, not necessarily in order.",
"default": {},
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/Target"
}
}
Eventually, VSCode renders the documentation in this way:
I investigated a little bit further. IntelliJ only renders the first line of the "description"
, so it's usually fine. VSCode renders the description as plain text. It is not able to understand any Markdown or HTML.
Ideally, schemars would parse the comments with an actual Mardown parser and render the content to plain text from there.
I couldn't find any off-the-shelf crate able to convert Markdown to plain text. schemars could probably leverage https://crates.io/crates/comrak or https://crates.io/crates/minimad, but there is work to do in both cases.
This currently compiles:
#[derive(JsonSchema)]
#[schemars(wasd, qwerty = "uiop")]
pub struct MyStruct;
It should cause a compile error to prevent people from mistyping or trying to use unsupported attributes
I have code like this
use schemars::JsonSchema;
#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)]
pub struct Event {
pub id: Option<i64>,
pub timestamp: DateTime<Utc>,
}
And I get the compiler error "the trait schemars::JsonSchema
is not implemented for `chrono::DateTimechrono::Utc". Even though it seems to me like https://github.com/GREsau/schemars/blob/5bf8b3075354a690561a7b81fcd1ed7fd56d87bf/schemars/src/json_schema_impls/chrono.rs pretty clearly implements DateTime among other DateTime combos.
Is there some import I'm missing or anything I should try to debug?
Hi,
I'm trying to use pulsar-rs (https://github.com/wyyerd/pulsar-rs, the apache pulsar rust client).
Pulsar offers JSONSchemas but only to draft03 (yet) due to https://github.com/FasterXML/jackson-module-jsonSchema.
mod a {
use super::*;
#[derive(JsonSchema)]
pub struct Config {
test: String,
}
}
mod b {
use super::*;
#[derive(JsonSchema)]
pub struct Config {
test2: String,
}
}
#[derive(JsonSchema)]
pub struct Config2 {
a_cfg: a::Config,
b_cfg: b::Config,
}
generates the following, invalid schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Config2",
"type": "object",
"required": [
"a_cfg",
"b_cfg"
],
"properties": {
"a_cfg": {
"$ref": "#/definitions/Config"
},
"b_cfg": {
"$ref": "#/definitions/Config"
}
},
"definitions": {
"Config": {
"type": "object",
"required": [
"test"
],
"properties": {
"test": {
"type": "string"
}
}
}
}
}
This is because there are two member structs with the same name, although they sit at different paths. This use case occurs in our systems because some (more top-level modules) export their own Config
structs which we then aggregate into one, global config for which we want to generate a schema for.
Is this expected behavior? What can we do to fix this? Would it make sense to extend schemars with support for this use case? It could automatically incorporate, e. g. the parent module name / the module path into the name of the definitions, such that these clashes can be avoided.
It would be useful to be able to annotate a container with something like #[schemars(extension = "x-foo-bar")]
and have those values appear in SchemaObject::extensions. I'd be happy to submit a PR if you'd be interested in it.
Received via email:
Is it possible to get it to output default values for the generated schema, as provide by Default/SmartDefault?
JSON Schema "default" keyword reference: https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.2
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
#[serde(default)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
}
The generated schema for MyStruct
should be:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"properties": {
"my_bool": {
"type": "boolean",
"default": false
},
"my_int": {
"type": "integer",
"format": "int32",
"default": 0
}
}
}
Note that we set default
on the properties, not on the top-level schema for MyStruct
.
It gets more complicated when we use #[serde(default)]
on fields as well as the struct, e.g.
fn ten_and_true() -> MyStruct2 {
MyStruct2 {
my_int: 10,
my_bool: true,
}
}
fn six() -> i32 {
6
}
#[derive(Default, Deserialize, Serialize, JsonSchema, Debug)]
#[serde(default = "ten_and_true")]
pub struct MyStruct2 {
#[serde(default = "six")]
pub my_int: i32,
pub my_bool: bool,
}
The generated schema for MyStruct2
should be:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct2",
"type": "object",
"properties": {
"my_bool": {
"type": "boolean",
"default": true
},
"my_int": {
"type": "integer",
"format": "int32",
"default": 6
}
}
}
fn ten_and_true() -> MyStruct2 {
MyStruct2 {
my_int: 10,
my_bool: true,
}
}
fn six() -> i32 {
6
}
#[derive(Default, Deserialize, Serialize, JsonSchema, Debug)]
#[serde(default)]
pub struct MyStruct {
pub my_int: i32,
pub my_bool: bool,
pub my_struct2: MyStruct2,
}
#[derive(Default, Deserialize, Serialize, JsonSchema, Debug)]
#[serde(default = "ten_and_true")]
pub struct MyStruct2 {
#[serde(default = "six")]
pub my_int: i32,
pub my_bool: bool,
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"properties": {
"my_bool": {
"type": "boolean",
"default": false
},
"my_int": {
"type": "integer",
"format": "int32",
"default": 0
},
"my_struct2": {
"allOf": [{"$ref": "#/definitions/MyStruct2"}],
"default": {
"my_bool": false,
"my_int": 0
}
}
},
"definitions": {
"MyStruct2": {
"type": "object",
"properties": {
"my_bool": {
"type": "boolean",
"default": true
},
"my_int": {
"type": "integer",
"format": "int32",
"default": 6
}
}
}
}
}
Note that the default for the my_struct2
property has different property defaults (false/0) than the defaults in the MyStruct2
definition (true/6). This is because:
{}
to MyStruct
results in MyStruct { my_int: 0, my_bool: false, my_struct2: MyStruct2 { my_int: 0, my_bool: false } }
{"my_struct2": {}}
results in MyStruct { my_int: 0, my_bool: false, my_struct2: MyStruct2 { my_int: 6, my_bool: true } }
dtolnays Serde_repr allows people to generate more compact json representations of Rust's enums. Currently when schemars generates a schema for an enum annotated with Serde_repr
, it generates an incorrect schema.
#[derive(serde_repr::Serialize_repr, schemars::JsonSchema)]
#[repr(u8)]
struct Kind {
One = 1,
Two = 2,
NotThree = 4,
}
The resulting schema looks like:
"Kind": {
"type": "string",
"enum": [
"One",
"Two",
"NotThree"
]
},
For the person using the documentation this is confusing, since they will read the documentation and expect strings, but they will receive integers. The correct output would be:
"Kind": {
"type": "string",
"enum": [
1,
2,
4
]
},
Received via email
Is there a way to get schemars to add serde aliased enum values to the generated schema? E.g. each aliased value shows up in the enum list like a regular enum value.
Thanks a lot for your amazing work on schemars and okapi!
I am using schemars through rocket_okapi to auto-generate docs for an API that I am writing. For this, I would like to give some meaningful examples for the parameters in my request JSON body, but I seem to have hit a conflict between the JSON Schema Validation specification and the OpenAPI 3.0 specification.
The Schema object in OpenAPI 3.0 expects the example for a Schema object to be placed in an example
key containing a single example, as opposed to the examples
array of example objects that seems to be currently generated by schemars. OpenAPI 3.0 does not allow examples
while JSON Schema Validation doesn't seem to support example
.
I have tried to generate an openapi.json using schemars with a documentation like so as advised in the attribute documentation for schemars:
fn schema_example_identifiers() -> Vec<String> {
vec!["my_id1".to_string(), "my_id2".to_string()]
}
fn schema_example_request() -> EntryRequest {
EntryRequest {
ids: schema_example_identifiers(),
}
}
#[derive(serde::Deserialize, serde::Serialize, JsonSchema)]
#[schemars(example = "schema_example_request")]
struct EntryRequest {
/// A list of entries from the database
#[schemars(example = "schema_example_identifiers")]
ids: Vec<String>,
}
The generated openapi.json does contain "examples"
entries for EntryRequest
:
"schemas": {
"EntryRequest": {
"examples": [
{
"ids": [
"my_id1",
"my_id2"
]
}
],
"type": "object",
"required": [
"ids"
],
"properties": {
"ids": {
"description": "A list of entries from the database",
"examples": [
[
"my_id1",
"my_id2"
]
],
"type": "array",
"items": {
"type": "string"
}
}
}
},
However, the examples don't show up in the Swagger UI. If I copy-paste the openapi.json to Swagger Editor, it tells me that "examples"
is not a valid field:
Everything works fine in Swagger Editor / Swagger UI after I rename examples
to example
and change from an array of example to a single example:
EntryRequest:
example:
ids:
- my_id1
- my_id2
type: object
required:
- ids
properties:
ids:
description: A list of entries from the database
example:
- my_id1
- my_id2
type: array
items:
type: string
From trying to understand the schemars
and okapi
codebases, I can see that examples could additionally get passed into the schema object using the extensions
member of okapi::openapi3::Parameter
structs, but I have no idea how to do this from within my API.
Could you please advise me how I could get the examples to show up correctly? If you would like to mentor me making a contribution to schemars
or okapi
to add support for the example
field, I would also be interested in helping out.
I would like schemars to honor serde(skip)
and schemars(skip)
to be able to omit internal datastructures. Ex:
#[derive(JsonSchema)]
struct Foo {
#[schemars(skip)]
bar: String
}
would generate a schema against which the input {}
validates.
schemars
does not seem to use unsafe code, which is very good :)
To prevent this from ever happening, add following line to the top:
#![forbid(unsafe_code)]
of https://github.com/GREsau/schemars/blob/master/schemars/src/lib.rs
and https://github.com/GREsau/schemars/blob/master/schemars_derive/src/lib.rs
This will make the package green in
https://github.com/rust-secure-code/cargo-geiger
Currently this causes an error like
mismatched types
expected reference &std::option::Option<_>
found reference &<task::Task as schemars::JsonSchema>::json_schema::_SchemarsDefaultSerialize<std::option::Option<std::time::Duration>>
I think it should mark that field as not required.
Thanks in advance.
Currently the schema properties are sorted alphabetical.
This might be desired in some cases. But could you allow an option to use the order of the fields in the structure?
This is handy because my id is now somewhere in the middle and when you have responses with a lot of optional fields this is very confusing. And it does not line up with how the actual response comes back.
Looking at this code (it might not be the right part of the code). You are using a Map
that is defined as:
/// The map type used by schemars types.
///
/// Currently a `BTreeMap`, but this may change a different implementation
/// with a similar interface in a future version of schemars.
pub type Map<K, V> = std::collections::BTreeMap<K, V>;
schemars/schemars/src/schema.rs
Line 433 in 4b37f96
Vec<(String, Schema)>
but then you have to add some searching by key.
The other option is adding some kind of order indicator to Schema
. But then Serde Serialize
will still not sort the list by that id.
There might also be other options.
So I think the first option is the better one.
I could help with this implementation if you want to.
Currently, doc comments on enum variants are ignored.
/// An enum representing the kind of the thing.
#[derive(schemars::JsonSchema)]
struct Kind {
/// The kind is one!
One,
/// The kind is two!
Two,
/// The kind is not three!
NotThree,
}
The resulting schema looks like:
"Kind": {
"type": "string",
"description": "An enum representing the kind of the thing.",
"enum": [
"One",
"Two",
"NotThree"
]
},
I searched the documentation of openapi, but it doesn't seem that they have proper support for documenting enum variants. I therefore suggest that the generated openapi.json should be something along the lines of
"Kind": {
"type": "string",
"description": "An enum representing the kind of the thing. \n\n## Variants \nOne: The kind is one! \nTwo: The kind is two! \nNotThree: The kind is not three!",
"enum": [
"One",
"Two",
"NotThree"
]
},
where we just append the variant documentation to the already existing documentation field, seperated by a newline or two and a header.
Swagger UI has a bug, ... already for 3 years. Were is handles enum
without a type
poorly.
See: swagger-api/swagger-ui#3761
A quick fix for this is adding a type: string item to the schema.
"RegionType": {
"description": "...",
"type": "string", <----Add_this_line
"enum": [
"Swamp",
"Desert",
"...",
"Unknown"
]
}
Adding the line above will change the output in Swagger UI from:
To This:
It would be cool if this can be fixed here.
Btw love this crate and the others you made. (I'm also using okapi and rocket_okapi.)
The https://crates.io/crates/url crate seems to be the common standard through the ecosystem. It would be nice if it could be handled so that we can generate schemas for structs containing URLs.
I would expect this code to compile:
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(JsonSchema, Serialize, Deserialize)]
pub struct Foo {
pub uri: Url
}
though currently it fails with:
--> src/model/api.rs:104:14
|
104 | pub uri: Url,
| ^^^ the trait `schemars::JsonSchema` is not implemented for `url::Url`
|
= note: required by `schemars::JsonSchema::add_schema_as_property`
Adding support for examples.
Currently strings will have an example of:
[
{
"list_of_int": [
0
],
"id": 0,
"name": "string",
"full_name": "string"
}
],
Where strings are always "string"
and int is always 0
If we add examples we can give some more info.
Maybe with a syntax like:
#[schemars(example = "This is the example string")]
Used like this:
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct Version {
#[schemars(example = "1.0.0")]
pub code: String,
#[schemars(example = "First release of our crate/application.")]
pub description: String,
}
This will result in something like:
{
"code": "1.0.0",
"description": "First release of our crate/application."
}
I don't know how this can also be done for int, but I think that is less of an issue.
For enums the first value is converted to string and that is used. So that does not have to change I think.
This issue is a repost of: GREsau/okapi#11
Something like this:
/tmp/b$ cat Cargo.toml
[package]
name = "b"
version = "0.1.0"
authors = ["up9cloud <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
schemars = "0.8"
/tmp/b$ cat src/main.rs
macro_rules! build_struct {
(
$id:ident { $($t:tt)* }
) => {
#[derive(Debug, schemars::JsonSchema)]
pub struct $id {
x: u8,
$($t)*
}
};
}
build_struct!(A { v: i32, });
fn main() {
println!("{:?}", A { x: 0, v: 1 });
}
/tmp/b$ cargo run
Compiling b v0.1.0 (/private/tmp/b)
error[E0425]: cannot find value `gen` in this scope
--> src/main.rs:12:22
|
12 | build_struct!(A { v: i32, });
| ^^^ not found in this scope
error[E0425]: cannot find value `schema_object` in this scope
--> src/main.rs:12:22
|
12 | build_struct!(A { v: i32, });
| ^^^ not found in this scope
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
error: could not compile `b`
To learn more, run the command again with --verbose.
If I remove schemars::JsonSchema
from derive, it works without errors.
Is there an unpushed 0.7.0-alpha-2 tag somewhere? It would be great to have the tag for the same commit that was publiched to crates.io. Thanks a lot!
I couldn't make JsonSchema
derive works with a macro that creates structs
and a enum
containing these structure
s. I keep getting an error cannot find value
gen in this scope
.
I made a gist showing a minimal example where the problem occurs.
If the JsonSchema
derive is commented on macro's call, the code works just fine.
error[E0425]: cannot find value `gen` in this scope
--> src/main.rs:27:24
|
27 | $inner($inner)
| ^^^^^^ not found in this scope
...
36 | / _macro!(
37 | | #[derive(Serialize, Deserialize, Debug, JsonSchema)]
38 | | Test {
39 | | #[derive(Serialize, Deserialize, Debug, JsonSchema)]
... |
42 | |
43 | | );
| |__- in this macro invocation
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
When I try to use the generated schema to validate data using Ajv I'm getting the following error:
Error: unknown format "uint32" is used in schema at path [...]
The error seems to be related to the integer format attribute. I couldn't find any mention of uint32
, uint
or anything of sorts in the JsonSchema spec.
Here is an example of the generated schema:
"portal": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
Am I doing something wrong here or is this a bug?
If Serde implements Serialize/Deserialize on it, then ideally Schemars should implement JsonSchema on it.
First of all, I want to say thank you for this fantastic library!
The Rust types I'm using with schemars already have lots of doc comments. I'd like schemas, via derive(JsonSchema), to skip those doc comments (they are too long). Ideally, I'd like to configure my own comments for just json schema generation. Is this possible?
Thanks!
i want to generate json schema from dynamic json value.
i don't know whether schemars support this function.
let data = r#"
{
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
}"#;
let v: Value = serde_json::from_str(data)? ;
I have a lot of types whose deserialization behavior allows for more types than the serialization does. For example:
// Deserialize is implemented such that any non-string JSON object is stringified
#[derive(Serialize)]
struct LenientString(String);
#[derive(JsonSchema, Serialize, Deserialize)]
struct Foo {
bar: LenientString
}
Therefore I would like to generate two schemas per type: A schema describing the input that is allowed, and a schema that describes the output that is guaranteed.
Is this kind of feature something you'd be interested in merging? I am on the fence as to whether this is sensible. In some languages I would've created separate input and output types, but as serde allowed me to do everything with one type this is what I ended up with. But I think that adding this feature to schemars is easier than refactoring my existing codebase.
Hello, and thank you for a great project!
I suspect I've encountered a bug (or I'm holding it wrong), but for some reason optional bools are set as required in definitions.
The version I'm using is 0.7.0-alpha-1
struct MyStruct {
pub foo: Option<bool>
}
pub fn get_schema() -> String {
let settings = schemars::gen::SchemaSettings::draft07().with(|s| {
s.option_nullable = false;
s.option_add_null_type = false;
});
let gen = settings.into_generator();
let schema = gen.into_root_schema_for::<config::MyStruct>();
serde_json::to_string_pretty(&schema).unwrap()
}
Generates the following schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"required": [
"foo"
],
"properties": {
"foo": {
"type": "boolean"
}
}
}
If I add #[serde(default)]
to foo
it removes the requirement.
Would it make sense to add an option to SchemaSettings
that says "Don't make Options required". I realize that the logic for this probably is more complicated since we have to take option_nullable
and option_add_null_type
into account, but having some kind of sensible default for this would make adoption easier.
Again, thanks for your great work. Much appreciated!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.