Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read #[validate(...)] attributes #78

Merged
merged 14 commits into from
Sep 18, 2021
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
run: cargo check --verbose --no-default-features
continue-on-error: ${{ matrix.allow_failure }}
working-directory: ./schemars
- if: matrix.rust == '1.37.0'
run: cargo update -p indexmap --precise 1.6.2
- name: Run tests
run: cargo test --verbose ${{ matrix.test_features }} --no-fail-fast
continue-on-error: ${{ matrix.allow_failure }}
Expand Down
9 changes: 6 additions & 3 deletions docs/_includes/examples/schemars_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
#[schemars(rename_all = "camelCase", deny_unknown_fields)]
pub struct MyStruct {
#[serde(rename = "thisIsOverridden")]
#[schemars(rename = "myNumber")]
#[schemars(rename = "myNumber", range(min = 1, max = 10))]
pub my_int: i32,
pub my_bool: bool,
#[schemars(default)]
Expand All @@ -15,8 +15,11 @@ pub struct MyStruct {
#[derive(Deserialize, Serialize, JsonSchema)]
#[schemars(untagged)]
pub enum MyEnum {
StringNewType(String),
StructVariant { floats: Vec<f32> },
StringNewType(#[schemars(phone)] String),
StructVariant {
#[schemars(length(min = 1, max = 100))]
floats: Vec<f32>,
},
}

fn main() {
Expand Down
11 changes: 8 additions & 3 deletions docs/_includes/examples/schemars_attrs.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@
},
"myNumber": {
"type": "integer",
"format": "int32"
"format": "int32",
"maximum": 10.0,
"minimum": 1.0
}
},
"additionalProperties": false,
"definitions": {
"MyEnum": {
"anyOf": [
{
"type": "string"
"type": "string",
"format": "phone"
},
{
"type": "object",
Expand All @@ -44,7 +47,9 @@
"items": {
"type": "number",
"format": "float"
}
},
"maxItems": 100,
"minItems": 1
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions docs/_includes/examples/validate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use schemars::{schema_for, JsonSchema};

#[derive(JsonSchema)]
pub struct MyStruct {
#[validate(range(min = 1, max = 10))]
pub my_int: i32,
pub my_bool: bool,
#[validate(required)]
pub my_nullable_enum: Option<MyEnum>,
}

#[derive(JsonSchema)]
pub enum MyEnum {
StringNewType(#[validate(phone)] String),
StructVariant {
#[validate(length(min = 1, max = 100))]
floats: Vec<f32>,
},
}

fn main() {
let schema = schema_for!(MyStruct);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}
64 changes: 64 additions & 0 deletions docs/_includes/examples/validate.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"required": [
"my_bool",
"my_int",
"my_nullable_enum"
],
"properties": {
"my_bool": {
"type": "boolean"
},
"my_int": {
"type": "integer",
"format": "int32",
"maximum": 10.0,
"minimum": 1.0
},
"my_nullable_enum": {
"anyOf": [
{
"type": "object",
"required": [
"StringNewType"
],
"properties": {
"StringNewType": {
"type": "string",
"format": "phone"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"StructVariant"
],
"properties": {
"StructVariant": {
"type": "object",
"required": [
"floats"
],
"properties": {
"floats": {
"type": "array",
"items": {
"type": "number",
"format": "float"
},
"maxItems": 100,
"minItems": 1
}
}
}
},
"additionalProperties": false
}
]
}
}
}
9 changes: 6 additions & 3 deletions schemars/examples/schemars_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
#[schemars(rename_all = "camelCase", deny_unknown_fields)]
pub struct MyStruct {
#[serde(rename = "thisIsOverridden")]
#[schemars(rename = "myNumber")]
#[schemars(rename = "myNumber", range(min = 1, max = 10))]
pub my_int: i32,
pub my_bool: bool,
#[schemars(default)]
Expand All @@ -15,8 +15,11 @@ pub struct MyStruct {
#[derive(Deserialize, Serialize, JsonSchema)]
#[schemars(untagged)]
pub enum MyEnum {
StringNewType(String),
StructVariant { floats: Vec<f32> },
StringNewType(#[schemars(phone)] String),
StructVariant {
#[schemars(length(min = 1, max = 100))]
floats: Vec<f32>,
},
}

fn main() {
Expand Down
11 changes: 8 additions & 3 deletions schemars/examples/schemars_attrs.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@
},
"myNumber": {
"type": "integer",
"format": "int32"
"format": "int32",
"maximum": 10.0,
"minimum": 1.0
}
},
"additionalProperties": false,
"definitions": {
"MyEnum": {
"anyOf": [
{
"type": "string"
"type": "string",
"format": "phone"
},
{
"type": "object",
Expand All @@ -44,7 +47,9 @@
"items": {
"type": "number",
"format": "float"
}
},
"maxItems": 100,
"minItems": 1
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions schemars/examples/validate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use schemars::{schema_for, JsonSchema};

#[derive(JsonSchema)]
pub struct MyStruct {
#[validate(range(min = 1, max = 10))]
pub my_int: i32,
pub my_bool: bool,
#[validate(required)]
pub my_nullable_enum: Option<MyEnum>,
}

#[derive(JsonSchema)]
pub enum MyEnum {
StringNewType(#[validate(phone)] String),
StructVariant {
#[validate(length(min = 1, max = 100))]
floats: Vec<f32>,
},
}

fn main() {
let schema = schema_for!(MyStruct);
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
}
64 changes: 64 additions & 0 deletions schemars/examples/validate.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MyStruct",
"type": "object",
"required": [
"my_bool",
"my_int",
"my_nullable_enum"
],
"properties": {
"my_bool": {
"type": "boolean"
},
"my_int": {
"type": "integer",
"format": "int32",
"maximum": 10.0,
"minimum": 1.0
},
"my_nullable_enum": {
"anyOf": [
{
"type": "object",
"required": [
"StringNewType"
],
"properties": {
"StringNewType": {
"type": "string",
"format": "phone"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"StructVariant"
],
"properties": {
"StructVariant": {
"type": "object",
"required": [
"floats"
],
"properties": {
"floats": {
"type": "array",
"items": {
"type": "number",
"format": "float"
},
"maxItems": 100,
"minItems": 1
}
}
}
},
"additionalProperties": false
}
]
}
}
}
43 changes: 14 additions & 29 deletions schemars/src/_private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ use crate::schema::{Metadata, Schema, SchemaObject};
use crate::JsonSchema;

// Helper for generating schemas for flattened `Option` fields.
pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(gen: &mut SchemaGenerator) -> Schema {
pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(
gen: &mut SchemaGenerator,
required: bool,
) -> Schema {
let mut schema = T::_schemars_private_non_optional_json_schema(gen);
if T::_schemars_private_is_option() {

if T::_schemars_private_is_option() && !required {
if let Schema::Object(SchemaObject {
object: Some(ref mut object_validation),
..
Expand All @@ -15,35 +19,16 @@ pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(gen: &mut SchemaGenerator
object_validation.required.clear();
}
}
schema
}

// Helper for generating schemas for `Option` fields.
pub fn add_schema_as_property<T: ?Sized + JsonSchema>(
gen: &mut SchemaGenerator,
parent: &mut SchemaObject,
name: String,
metadata: Option<Metadata>,
required: bool,
) {
let mut schema = gen.subschema_for::<T>();
schema = apply_metadata(schema, metadata);

let object = parent.object();
if required && !T::_schemars_private_is_option() {
object.required.insert(name.clone());
}
object.properties.insert(name, schema);
schema
}

pub fn apply_metadata(schema: Schema, metadata: Option<Metadata>) -> Schema {
match metadata {
None => schema,
Some(ref metadata) if *metadata == Metadata::default() => schema,
Some(metadata) => {
let mut schema_obj = schema.into_object();
schema_obj.metadata = Some(Box::new(metadata)).merge(schema_obj.metadata);
Schema::Object(schema_obj)
}
pub fn apply_metadata(schema: Schema, metadata: Metadata) -> Schema {
if metadata == Metadata::default() {
schema
} else {
let mut schema_obj = schema.into_object();
schema_obj.metadata = Some(Box::new(metadata)).merge(schema_obj.metadata);
Schema::Object(schema_obj)
}
}
Loading