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

Annotation for example values #11

Closed
Geigerkind opened this issue Jan 26, 2020 · 17 comments
Closed

Annotation for example values #11

Geigerkind opened this issue Jan 26, 2020 · 17 comments

Comments

@Geigerkind
Copy link

I was thinking about an annotation on the data type maybe.

@williamdes
Copy link

williamdes commented May 2, 2020

I need this !
Having string is ugly as a default example value

{
  "code": "string",
  "description": "string"
}
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;

#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all="camelCase")]
pub struct Version {
    pub code: String,
    pub description: String,
}

@williamdes
Copy link

@GREsau is it Rust newbie doable ?

@ralpha
Copy link
Collaborator

ralpha commented May 18, 2020

What syntax should be used if this is implemented? Something like:

#[okapi(example = "This is the example string")]

Or because this is part of schemars:

#[schemars(example = "This is the example string")]

Used like this:

#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all="camelCase")]
pub struct Version {
    #[schemars(example = "1.0.0")]
    pub code: String,
    #[schemars(example = "First release of our crate/application.")]
    pub description: String,
}

I created a new issue in Schemars for this. Linked below.

@GREsau
Copy link
Owner

GREsau commented Jun 11, 2020

This is currently implemented in Schemars (GREsau/schemars#23), but unfortunately this doesn't work for okapi because OpenAPI 3.0 does not understand JSON Schema's "examples" keyword (see "example vs examples" here)

We could fix this by adding a new Visitor to SchemaSettings::openapi3 in schemars (here) which changes all "examples" in schemas to "example", e.g. it could transform { "type": "number", "examples": [100, 200] } to { "type": "number", "example": 100 }

@GREsau
Copy link
Owner

GREsau commented Jun 12, 2020

I've now implemented the above change, so if you attach a #[schemars(example = "some_fn")] attribute to your fields/types, it should now be visible in swagger!

You can try it out now in rocket-okapi v0.6.0-alpha-1

@williamdes
Copy link

Thank you !
I will try it after the night 🇫🇷
I am having some expected struct `okapi::openapi3::Info`, found a different struct `okapi::openapi3::Info strange errors for now (https://github.com/mountains/permafrost/tree/next)

@GREsau
Copy link
Owner

GREsau commented Jun 12, 2020

Ah you'll also need to update okapi to okapi 0.5.0-alpha-1

@williamdes
Copy link

error[E0277]: the trait bound `ressources::Version::Version: rocket_okapi::JsonSchema` is not satisfied
 --> src/routes/version.rs:4:1
  |
4 | #[openapi]
  | ^^^^^^^^^^ the trait `rocket_okapi::JsonSchema` is not implemented for `ressources::Version::Version`
  |
  = note: required because of the requirements on the impl of `rocket_okapi::response::OpenApiResponder<'_>` for `rocket_contrib::json::Json<ressources::Version::Version>`
  = note: required by `rocket_okapi::response::OpenApiResponder::responses`
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

Sorry to ask this here, but I have no idea on how to fix this for now

@GREsau
Copy link
Owner

GREsau commented Jun 13, 2020

What version of okapi and schemars are you referencing in your Cargo.toml? Make sure they match the dependency versions listed on https://crates.io/crates/rocket_okapi/0.6.0-alpha-1

williamdes added a commit to mountains/permafrost that referenced this issue Jun 13, 2020
williamdes added a commit to mountains/permafrost that referenced this issue Jun 13, 2020
williamdes added a commit to mountains/permafrost that referenced this issue Jun 13, 2020
williamdes added a commit to mountains/permafrost that referenced this issue Jun 13, 2020
@williamdes
Copy link

williamdes commented Jun 13, 2020

Thank you for the support !
Last error is fixed by: mountains/permafrost@bb5bd7a (upgrading schemars)

And I implemented my first example with mountains/permafrost@7d4229f

And it looks very more sexy on Swagger 🚀
I am so happy to have examples available !

@ThouCheese
Copy link
Contributor

ThouCheese commented Jun 14, 2020

What version of okapi and schemars are you referencing in your Cargo.toml?

@GREsau It might be worthwhile to export okapi and schemars in rocket_okapi, so it's impossible to use incorrect versions together, and also clean up people's cargo.toml a bit. We can put schemars behind a feature flag that is on by default, since you will almost always need it. If you're open to this I can make a PR. :)

@ralpha
Copy link
Collaborator

ralpha commented Jun 17, 2020

I Just tested this out and works correct.

Just for anyone in the future here is some example code:

#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema)]
#[schemars(example = "example_item")]
pub struct Item {
    pub id: i32,
    pub name: Option<String>,
    pub numbers: Vec<i32>,
}

fn example_item() -> Item{
    Item{
        id: 5,
        name: Some("This is just the perfect name".to_owned()),
        numbers: vec![20,21],
    }
}

Or you can do a function in the impl:

#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema)]
#[schemars(example = "Self::example")]
pub struct Item {
    pub id: i32,
    pub name: Option<String>,
    pub numbers: Vec<i32>,
}

impl Item{
    pub fn new() -> Self{
        Self::default()
    }

    // This function does not have to be public (if it is in the same module).
    pub fn example() -> Self{
        Self{
            id: 5,
            name: Some("This is just the perfect name".to_owned()),
            numbers: vec![20,21],
        }
    }
}

@GREsau Just one thing I noted is that when you do this the order of the fields is not order correctly with the preserve_order flag.
The order is currently alphabetical, not the order of my fields. (without the example the order was correct, so is somewhere in the new code, structs that do not have examples yet are ordered correctly)
I'll implement it for a few more of my structs and see if there is any other problems I find.

@ralpha
Copy link
Collaborator

ralpha commented Jun 17, 2020

When implementing (although not finished with it yet) I had to add a trait SchemaExample

pub trait SchemaExample{
    fn example() -> Self;
}

Because I have some generics with nested objects. Example:

#[derive(Serialize, Deserialize, Clone, Debug, Default, JsonSchema)]
#[schemars(example = "Self::example")]
pub struct ApiItem<D> where
    D: ApiObject + Serialize + SchemaExample{
    /// A unique string identifier for this type.
    #[serde(rename = "_type")]
    pub type_: String,
    /// Links the various related items.
    #[serde(rename = "_links")]
    pub links: ApiItemLinks,
    /// The included data item.
    #[serde(flatten)]
    pub data: D,
    /// Server base url.
    /// Not included in response.
    #[serde(skip)]
    pub base_url: String,
}

impl<D> SchemaExample for ApiItem<D> where D: SchemaExample + Serialize + ApiObject{
    fn example() -> Self{
        Self{
            type_: "example".to_owned(),
            links: ApiItemLinks::example(),
            data: D::example(),
            base_url: "".to_owned(),
        }
    }
}

Otherwise I could not get the example function of the nested generic items.
Using this also allows me to specify the example function for nested objects easily.
So if you are considering doing this for your codebase you might want to do something similar.

Also note that you can then use #[schemars(example = "Self::example")] which looks quite nice.

This trait could also be implemented in okapi or schemars itself and then can be used by all projects. In that case specifying the #[schemars(example = "Self::example")] might not even be needed. @GREsau what do you thing?

Edit: #[schemars(example = "Self::<D>::example")] should just be #[schemars(example = "Self::example")]

@GREsau
Copy link
Owner

GREsau commented Jun 18, 2020

I noted is that when you do this the order of the fields is not order correctly with the preserve_order flag.

Ah, I think you'll need to enable the preserve_order feature flag of serde_json too. Examples are stored as serde_json::Value objects, which like schemars, will use BTreeMap by default

@ralpha
Copy link
Collaborator

ralpha commented Jun 18, 2020

That was exactly what the problem was!
Again with code: 😉

serde_json = { version = "1.0", features = ["preserve_order"] }
# Also for schemars
schemars = { version = "0.8.0-alpha-4", features = ["preserve_order"] }

@Type1J
Copy link

Type1J commented Mar 29, 2021

Is there a reason why this isn't closed?

mautamu pushed a commit to mautamu/okapi that referenced this issue Apr 23, 2021
@ralpha
Copy link
Collaborator

ralpha commented Sep 8, 2021

This is already implemented and merged, closing issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants