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

OpenApi 3 schema generation is flawed for Maps #1036

Open
krissrex opened this issue Jan 15, 2024 · 5 comments
Open

OpenApi 3 schema generation is flawed for Maps #1036

krissrex opened this issue Jan 15, 2024 · 5 comments

Comments

@krissrex
Copy link
Contributor

There are several issues with the OpenApi schema generation, and I tried to fix them in my proof-of-concept repo at https://github.com/krissrex/http4k-openapi-annotations/blob/master/src/main/kotlin/no/krex/http4kopenapi/annotations/LifligAutoJsonToJsonSchema.kt . It seems to work, but the code feels slightly messy. (Not ready to PR anything).

The most important issues I found (and fixed) are these:

  1. Correct schema for map-of-maps: mapOf("key" to mapOf("keyInner" to 5)) -> { "additionalProperties": { "additionalProperties": { "type": "number} } } .
  2. Correct schema for map-of-various: mapOf("key" to 1, "key2" to true) -> "additionalProperties": true .

The schema generation is based on the JSON, not the classes. And when a map gets its schema, the example keys are treated like object-properties, not example values, and fed into an Object schema as properties. Instead, we want the values of the example to inform the type of additionalProperties.type. And if the inner values are maps, the schema should not be additionalProperties.properties.additionalProperties, but additionalProperties.additionalProperties.type.


Example map:

// val myMap: Map<String, Map<String, Double>>

  myMap = mapOf(
                        "outerKey1" to mapOf("innerKey1" to 3.14, "innerKey12" to 3.14159),
                        "outerKey2" to mapOf("innerKey2" to 2.71)
                    ),

Ignore any json formatting issues etc, I trimmed the examples to focus on the important parts

Example of current (incorrect) schema:

"myMap": {
            "additionalProperties": {
              "properties": {
                "outerKey1": {
                  "additionalProperties": {
                    "properties": {
                      "innerKey1": {
                        "example": 3.14,
                        "format": "double",
                        "type": "number"
                      },
                      "innerKey12": {
                        "example": 3.14159,
                        "format": "double",
                        "type": "number"
                      }
                    },
                    "example": {
                      "innerKey1": 3.14,
                      "innerKey12": 3.14159
                    },
                    "type": "object"
                  },
                  "type": "object"
                },
                "outerKey2": {
                  "additionalProperties": {
                    "properties": {
                      "innerKey2": {
                        "example": 2.71,
                        "format": "double",
                        "type": "number"
                      }
                    },
                    "example": {
                      "innerKey2": 2.71
                    },
                    "type": "object"
                  },
                  "type": "object"
                }
              },
              "example": {
                "outerKey1": {
                  "innerKey1": 3.14,
                  "innerKey12": 3.14159
                },
                "outerKey2": {
                  "innerKey2": 2.71
                }
              },
              "type": "object"
            },
            "type": "object"
          }

Correct schema:

"myMap": {
  "additionalProperties": {
    "additionalProperties": {
      "example": 3.14,
      "type": "number"
    },
    "type": "object"
  },
  "type": "object"
}

For maps of various types:

// val myMapWithAnything: Map<String, Any>

 myMapWithAnything = mapOf("number" to 4, "bool" to true)

the correct is (not 100% sure about the example-property here):

"myMapWithAnything": {
    "additionalProperties": true,
    "example": {
      "number": 4,
      "bool": true
    },
    "type": "object"
  }

For maps of a primitive type:

// val primitiveMap: Map<String, Int>

mapOf("key" to 1)

the correct is:

"primitiveMap": {
  "additionalProperties": {
    "type": "number"
  }
}
@krissrex
Copy link
Contributor Author

krissrex commented Feb 5, 2024

Seems to be issues with maps of ArrayList too. The keys will get a schema saying object, not array.

@tamj0rd2
Copy link
Contributor

tamj0rd2 commented Feb 12, 2024

I really wish it was possible to provide your own schemaGenerator like in the OpenAPI2 implementation. I'm using a library which is able to produce Json schemas which work perfectly for my use case, but am unable to utilise them with http4k

Edit: the library is Kondor. See #1063

@daviddenton
Copy link
Member

daviddenton commented Feb 12, 2024

I really wish it was possible to provide your own schemaGenerator like in the OpenAPI2 implementation. I'm using a library which is able to produce Json schemas which work perfectly for my use case, but am unable to utilise them with http4k

This is possible - the creation of the Schema is abstracted behind the JsonSchemaCreator interface which is used in both the OpenApi2 and OpenApi3 implementations.

@tamj0rd2
Copy link
Contributor

I really wish it was possible to provide your own schemaGenerator like in the OpenAPI2 implementation. I'm using a library which is able to produce Json schemas which work perfectly for my use case, but am unable to utilise them with http4k

This is possible - the creation of the Schema is abstracted behind the JsonSchemaCreator interface which is used in both the OpenApi2 and OpenApi3 implementations.

@daviddenton I couldn't see a way to supply this in the OpenApi3 implementation. So I've submitted a PR for that here - #1058

@krissrex
Copy link
Contributor Author

I really wish it was possible to provide your own schemaGenerator like in the OpenAPI2 implementation. I'm using a library which is able to produce Json schemas which work perfectly for my use case, but am unable to utilise them with http4k

Mind sharing the name of the library? I might want to use it myself.

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

3 participants