Using generic schema as type for another generic schema
Description
Hi, as mentioned in the title, I want to use a generic schema as a type for another generic schema.
The problem
All aliases for GenericStructA<T> prompt error messages.
What do I expect?
GenericStructAString, GenericStructAInt, and GenericStructANotGenericStruct will create references to GenericStructBString, GenericStructBInt, and GenericStructBNotGenericStruct. Or even better I don't have to create those aliases for GenericStructB<T> and they will be created automatically by creating those aliases for GenericStructA<T>
// main.rs
use actix_web::{middleware::Logger, App, HttpServer, Result};
use std::{error::Error, net::Ipv4Addr};
use utoipa::{OpenApi, ToSchema};
use utoipa_swagger_ui::SwaggerUi;
#[derive(ToSchema)]
#[aliases(GenericStructAString = GenericStructA<String>, GenericStructAInt = GenericStructA<i32>, GenericStructANotGenericStruct = GenericStructA<NotGenericStruct>)]
pub struct GenericStructA<T> {
pub field_a: String,
pub field_b: i32,
pub generic_struct_b: GenericStructB<T>,
}
#[derive(ToSchema)]
#[aliases(GenericStructBString = GenericStructB<String>, GenericStructBInt = GenericStructB<i32>, GenericStructBNotGenericStruct = GenericStructB<NotGenericStruct>)]
pub struct GenericStructB<T> {
pub field_c: bool,
pub field_d: f32,
pub generic_field: T,
}
#[derive(ToSchema)]
pub struct NotGenericStruct {
pub field_e: String,
pub field_f: i32,
}
#[actix_web::main]
async fn main() -> Result<(), impl Error> {
#[derive(OpenApi)]
#[openapi(
paths(),
components(schemas(
NotGenericStruct,
GenericStructBString,
GenericStructBInt,
GenericStructBNotGenericStruct,
GenericStructAString,
GenericStructAInt,
GenericStructANotGenericStruct
))
)]
struct ApiDoc;
let openapi = ApiDoc::openapi();
HttpServer::new(move || {
App::new().wrap(Logger::default()).service(
SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi.clone()),
)
})
.bind((Ipv4Addr::UNSPECIFIED, 8080))?
.run()
.await
}
# Cargo.toml
[package]
name = "testing"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "4.3.1"
utoipa = { version = "3", features = ["actix_extras"] }
utoipa-swagger-ui = { version = "3", features = ["actix-web"] }
This is probably something that needs a little or perhaps even more investigation and exploration. I don't have the time to get to this right now, but perhaps this could be addressed in future.
The generics are quite troublesome because of the design of the utoipa library. Since the utoipa is compile-time the types need to be know before hand at the declaration level and not when they are being used at runtime. This is the reason why aliases are used as a first place to allow generic types in some form but the current implementation does not take into account existing aliases when generating spec for a generic type that already has aliases.
A word of caution. It might be possible to support this behavior but same goes other way as well. This functionality might be difficult or near impossible to implement.