-
Notifications
You must be signed in to change notification settings - Fork 224
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
Support NewType pattern by flattening #663
Comments
#655 is related, and has pointers to where the improvements might be needed in utoipa to better support newtype pattern. |
Better newtype support would be really great. 💙 In my case, where I wrap |
Thanks for the comments on this! I actually switched to using tuple types as my new type wrappers so this isn't an issue for me right now, but I agree it would be a 'nice to have'. Not sure I have the capacity to contribute on this at the moment as I'm still too unfamiliar with Rust & macros, but I'll leave it up to the maintain if they want to close it. (Might be worth just tracking #655) |
Typically the new type pattern is a struct with one unnamed field e.g. According to https://serde.rs/container-attrs.html#transparent, adding a support for // api/user.rs
#[derive(Debug, Deserialize, ToSchema, IntoParams, garde::Validate)]
#[serde(transparent)] // <-- note here
pub struct CreateUserRequest {
#[param(min_length = 3, max_length = 64)]
#[garde::garde(dive)]
pub username: Username,
} |
@juhaku the problem is some parameters are not supported for new types/enum fields: #[derive(Debug, Clone, Deref, ToSchema, Serialize, Deserialize, Validate, Default, PartialEq)]
pub struct ByteLength(
#[schema(minimum = 1)]
#[garde(range(min = 1))]
u32,
); In this case, the
Not being able to specify such parameter makes the new type a lot let useful IMHO. |
True, the unnamed fields do not support macro attributes at the moment at all. And all the attributes for new types need to be defined on the type itself. Sure this kind of support would be quite beneficial so the validation attributes could be defined for new types as well. @absolutejam @jayvdb @JMLX42 @asaaki Regarding new type pattern in general (also discussed here #655), in the coming 5.0.0 release utoipa will have support for global aliases https://github.com/juhaku/utoipa/tree/master/utoipa-config. These global aliases allows users to define aliases how certain types should be treated across the utoipa. This will also solve the @jayvdb mentioned issue with UUID warpping #655 (comment). pub struct FooId(pub uuid::Uuid);
// then in build.rs
utoipa_config::Config::new().alias_for("FooId", "Uuid").write_to_file(); There is test crate for testing and demonstrating the functionality: https://github.com/juhaku/utoipa/tree/master/utoipa-config/config-test-crate. You might want to look into |
That's great news @juhaku . The problem remains that those are global aliases for one or more types. But I don't see how to create a new schema using a newtype that specializes an existing generic type. Having to manually list the types to alias in I don't need to replace a type with another type. I need to set the type for a generic. Example: struct Id<T> {
value: T,
}
#[derive(ToSchema)]
struct Uuid(Id<uuid::Uuid>) This way, I can write a generic implementation of my JSON:API HTTP responses, but template the primary data with the actual type. Here is my example: In my #[derive(ToSchema)]
struct Response<T> {
data: Vec<T>,
} Then in my struct Book {
attributes: BookAttributes,
}
struct BookAttributes {
author: String,
}
#[derive(ToSchema)]
struct BookResponse(jsonapi::Response<Book>) That would generate the following JSON response: {
"data": [
{
"attributes": {
"author": "Jean-Luc Picard"
}
}
]
} I might be mistaken, but this is still not possible. |
Amazing work on this crate!
I'm just testing it at the moment and my current approach is to use a request struct containing my domain objects - which leverage the NewType pattern. Then I have a single type that I can validate in my handler (using garde), like so:
And as far as the user is concerned, they're just sending a
String
, butserde
(and the#[serde(transparent)]
annotation) make this wrapping step invisible to the user.However, in the Swagger UI, I see the schema is presented as:
Would it be possible to 'flatten' this so that it is still represented as
{ "name": "string" }
to the user (Both in the params and the response), and so that I don't have to addUsername
to the schema? I tried using a mix ofinline
,explode
andvalue_type
to see if any of them did what I needed, but they don't seem to.The text was updated successfully, but these errors were encountered: