poem icon indicating copy to clipboard operation
poem copied to clipboard

Generated OpenAPI spec with generics results in non-RFC3986-compliant $ref

Open chikko80 opened this issue 1 year ago • 0 comments

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_"
                }
              }
            }
          },
          ...
        }
      }
    }
  },

chikko80 avatar Oct 11 '23 11:10 chikko80