poem
poem copied to clipboard
Generated OpenAPI spec with generics results in non-RFC3986-compliant $ref
Actual Behaviour
If you specify generics in your response type, the resulting OpenAPI specification becomes invalid due to non-RFC3986-compliant $ref values.
Example:
#[derive(Object)]
struct Example {
number: i32,
}
#[derive(Object)]
struct MetaData {
count: usize,
page: i32,
size: i32,
total_count: i64,
}
#[derive(Object)]
struct GenericResponse<R>
where
R: Send + Sync + ParseFromJSON + ToJSON,
{
meta: MetaData,
data: Vec<R>,
}
struct Api;
#[OpenApi(internal)]
impl Api {
#[oai(path = "/", method = "get")]
async fn test(&self) -> Result<Json<GenericResponse<Example>>, Error> {
return Err(Error::BadRequest);
}
}
Output:
{
...
"paths": {
"/": {
"get": {
"responses": {
"200": {
...
"content": {
"application/json; charset=utf-8": {
"schema": {
"$ref": "#/components/schemas/GenericResponse<Example>"
}
}
}
},
...
}
}
}
},
"components": {
"schemas": {
...
"GenericResponse<Example>": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/MetaData"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Example"
}
}
}
},
...
}
}
}
Error (https://editor.swagger.io/):
Semantic error at paths./.get.responses.200.content.application/json; charset=utf-8.schema.$ref
$ref values must be RFC3986-compliant percent-encoded URIs
Jump to line 16
Semantic error at components.schemas.GenericResponse<Example>
Component names can only contain the characters A-Z a-z 0-9 - . _
Jump to line 29
The presence of < and > in the schema name due to generics is causing the $ref value to be non-compliant with RFC3986.
Expected Behavior:
The name for the generic type should be appropriately formatted in the generated OpenAPI spec to ensure that all $ref values are RFC3986-compliant.
Possible Solution:
Consider implementing a mechanism to percent-encode, or otherwise sanitize (substitute), object names that include generics to avoid this issue.
I am not very familiar with the overall OpenAPI specification, but I'd probably go for substitution if there isn't any argument against it.
@sunli829 please share your thoughts on this
{
...
"paths": {
"/": {
"get": {
"responses": {
"200": {
...
"content": {
"application/json; charset=utf-8": {
"schema": {
"$ref": "#/components/schemas/GenericResponse_Example_"
}
}
}
},
...
}
}
}
},