Attribute for defining examples (#23)

This commit is contained in:
Graham Esau 2020-05-17 16:41:19 +01:00
parent 19b9bef395
commit e259955809
4 changed files with 88 additions and 3 deletions

View file

@ -0,0 +1,25 @@
mod util;
use schemars::JsonSchema;
use serde::Serialize;
use util::*;
#[derive(Default, Debug, JsonSchema, Serialize)]
#[schemars(example = "Struct::default", example = "null")]
pub struct Struct {
#[schemars(example = "eight", example = "null")]
foo: i32,
bar: bool,
#[schemars(example = "null")]
baz: Option<&'static str>,
}
fn eight() -> i32 {
8
}
fn null() -> () {}
#[test]
fn examples() -> TestResult {
test_default_generated_schema::<Struct>("examples")
}

View file

@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Struct",
"examples": [
{
"bar": false,
"baz": null,
"foo": 0
},
null
],
"type": "object",
"required": [
"bar",
"foo"
],
"properties": {
"bar": {
"type": "boolean"
},
"baz": {
"examples": [
null
],
"type": [
"string",
"null"
]
},
"foo": {
"examples": [
8,
null
],
"type": "integer",
"format": "int32"
}
}
}

View file

@ -16,7 +16,7 @@ pub struct Attrs {
pub title: Option<String>,
pub description: Option<String>,
pub deprecated: bool,
// TODO pub example: Option<syn::Path>,
pub examples: Vec<syn::Path>,
}
#[derive(Debug)]
@ -111,6 +111,12 @@ impl Attrs {
}
}
Meta(NameValue(m)) if m.path.is_ident("example") => {
if let Ok(fun) = parse_lit_into_path(errors, attr_type, "example", &m.lit) {
self.examples.push(fun)
}
}
Meta(_meta_item) => {
// TODO uncomment this for 0.8.0 (breaking change)
// https://github.com/GREsau/schemars/issues/18

View file

@ -3,13 +3,14 @@ use attr::Attrs;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{ToTokens, TokenStreamExt};
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone)]
pub struct SchemaMetadata<'a> {
pub title: Option<&'a str>,
pub description: Option<&'a str>,
pub deprecated: bool,
pub read_only: bool,
pub write_only: bool,
pub examples: &'a [syn::Path],
pub default: Option<TokenStream>,
}
@ -36,7 +37,10 @@ impl<'a> SchemaMetadata<'a> {
title: attrs.title.as_ref().and_then(none_if_empty),
description: attrs.description.as_ref().and_then(none_if_empty),
deprecated: attrs.deprecated,
..Default::default()
examples: &attrs.examples,
read_only: false,
write_only: false,
default: None,
}
}
@ -80,6 +84,17 @@ impl<'a> SchemaMetadata<'a> {
});
}
if !self.examples.is_empty() {
let examples = self.examples.iter().map(|eg| {
quote! {
schemars::_serde_json::value::to_value(#eg())
}
});
setters.push(quote! {
metadata.examples = vec![#(#examples),*].into_iter().flatten().collect();
});
}
if let Some(default) = &self.default {
setters.push(quote! {
metadata.default = #default.and_then(|d| schemars::_serde_json::value::to_value(d).ok());