open-api-spex / open_api_spex

Open API Specifications for Elixir Plug applications
Mozilla Public License 2.0
681 stars 177 forks source link

Problem with nested oneOf in allOf #594

Closed GregorGrasselli closed 2 months ago

GregorGrasselli commented 5 months ago

There seems to be a bug when creating a struct from a schema that has a nested oneOf inside an allOf

We take a schema that seems to work correctly:

schema = %OpenApiSpex.Schema{
...(7)>   allOf: [
...(7)>     %OpenApiSpex.Schema{
...(7)>       type: :object,
...(7)>       properties: %{p: %OpenApiSpex.Schema{type: :string}},
...(7)>       required: [:p]
...(7)>     },
...(7)>     %OpenApiSpex.Schema{
...(7)>       oneOf: [
...(7)>         %OpenApiSpex.Schema{
...(7)>           type: :object,
...(7)>           properties: %{a: %OpenApiSpex.Schema{type: :string}},
...(7)>           required: [:a]
...(7)>         },
...(7)>         %OpenApiSpex.Schema{
...(7)>           type: :object,
...(7)>           properties: %{b: %OpenApiSpex.Schema{type: :string}},
...(7)>           required: [:b]
...(7)>         }
...(7)>       ]
...(7)>     }
...(7)>   ]
...(7)> }

iex(10)> OpenApiSpex.Cast.cast(schema, %{p: "str", b: "qwe"})
{:ok, %{p: "str", b: "qwe"}}

Using it to define a struct produces a struct without the keys :a and :b:

ex(15)> defmodule Test do
...(15)> OpenApiSpex.schema %{
...(15)>   allOf: [
...(15)>     %OpenApiSpex.Schema{
...(15)>       type: :object,
...(15)>       properties: %{p: %OpenApiSpex.Schema{type: :string}},
...(15)>       required: [:p]
...(15)>     },
...(15)>     %OpenApiSpex.Schema{
...(15)>       oneOf: [
...(15)>         %OpenApiSpex.Schema{
...(15)>           type: :object,
...(15)>           properties: %{a: %OpenApiSpex.Schema{type: :string}},
...(15)>           required: [:a]
...(15)>         },
...(15)>         %OpenApiSpex.Schema{
...(15)>           type: :object,
...(15)>           properties: %{b: %OpenApiSpex.Schema{type: :string}},
...(15)>           required: [:b]
...(15)>         }
...(15)>       ]
...(15)>     }
...(15)>   ]
...(15)> }
...(15)> end
iex(16)> %Test{}
%Test{p: nil}
iex(17)> %Test{p: "asdf", a: "burek"}
** (KeyError) key :a not found
    expanding struct: Test.__struct__/1
    iex:17: (file)
GregorGrasselli commented 4 months ago

I tried what happens when I add this to an endpoint and send a valid request. Validation succeeds, but the body_params that are created are missing the keys specified under the oneOf part.

GregorGrasselli commented 2 months ago

Turns out this can be fixed by just not using structs in any of the schemas that have oneOf in their top level. I think it might make sense to change the default value for struct? in such cases.