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

Fix oneOf/allOf/anyOf and schema module in Discriminator mapping #455

Merged
merged 34 commits into from
Oct 19, 2022

Conversation

lucacorti
Copy link
Contributor

@lucacorti lucacorti commented May 23, 2022

This is the same as #440, with master merged and a fix to allow Schema modules to be used in Discriminator mappings instead of relying on the title:

%Schema{
      type: :object,
      oneOf: [
          MySchema,
          MyOtherSchema
     ],
     discriminator: %Discriminator{
     propertyName: "aprop",
     mapping: %{
      "MY_SCHEMA" => MySchema,
      "MY_OTHER_SCHEMA" => MyOtherSchema
    }
  }
}

Without this casting does not currently work proprerly for schemas with oneOf and Discriminator. It also removes the discriminator propertyName from the path, avoiding it to be added to the JSON pointers in validation errors.

@igormq
Copy link
Contributor

igormq commented Jun 16, 2022

up

@igormq
Copy link
Contributor

igormq commented Jul 1, 2022

hey, someone here willing to merge this pr ?

@mbuhot
Copy link
Collaborator

mbuhot commented Jul 7, 2022

@igormq It's difficult to review and merge this PR with so many commits and changes.
Can the branch be squashed down to a smaller number of commits with clear messages describing each change?


# Merge 2 maps considering as equal keys that are atom or string representation
# of that atom. Atom keys takes precedence over string ones.
def merge_maps(map1, map2) do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not implemented this and am not sure what the functions achieves. @albertored can you take a look?

test/cast/all_of_test.exs Outdated Show resolved Hide resolved
test/cast/any_of_test.exs Outdated Show resolved Hide resolved
Copy link
Contributor

@zorbash zorbash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

lib/open_api_spex/cast.ex Outdated Show resolved Hide resolved
@lucacorti
Copy link
Contributor Author

Can this be merged? I've been running this in production for a few months as it fixes a few issues with the existing code where Discriminator is not working. I guess improvements can be done in subsequent PRs.

end
defp find_discriminator_schema(discriminator, _mappings, schemas)
when is_atom(discriminator) and not is_nil(discriminator),
do: Enum.find(schemas, &Kernel.==(&1."x-struct", discriminator))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Kernel.== necessary here? can it be:

Suggested change
do: Enum.find(schemas, &Kernel.==(&1."x-struct", discriminator))
do: Enum.find(schemas, & &1."x-struct" == discriminator)

?

@mbuhot mbuhot merged commit 3bd7d9a into open-api-spex:master Oct 19, 2022
@lucacorti lucacorti deleted the fix-xxxOf branch October 19, 2022 08:04
albertored added a commit to athonet-open/open_api_spex that referenced this pull request Oct 19, 2022
@@ -40,7 +40,7 @@ defmodule OpenApiSpex.Cast.Discriminator do
defp cast_discriminator(%_{value: value, schema: schema} = ctx) do
{discriminator_property, mappings} = discriminator_details(schema)

case value["#{discriminator_property}"] || value[discriminator_property] do
case value["#{discriminator_property}"] do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbuhot I don't remember if I was the one that originally added this line but I think this was needed to support discriminators where the property is an atom, it is indirectly tested in the test you removed in this same commit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a scenario where the discriminator property is an atom?
The test was casting a map where all keys were already atoms, I'm not sure when that would be required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are use cases but I don't have a particular one in mind.

My reasoning was that since it is possible to cast an object with atom keys it should be possible also when the discriminator property is an atom

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igormq Is there a scenario you have where you need to cast data that already has atom keys?
I'm open to including the functionality, I just want to make sure it's not a hack to fix some other bug we might have :)

024e7d2

@Aduril
Copy link

Aduril commented Nov 9, 2022

Heho,
I think this still doesn't fix #387 or am I wrong? :-/

The example from the tests still renders a wrong json.

  defmodule AppointmentType do
    require OpenApiSpex

    OpenApiSpex.schema(%{
      title: "AppointmentType",
      type: :object,
      properties: %{
        appointment_type: %Schema{
          type: :string
        }
      },
      required: [:appointment_type]
    })
  end

  defmodule TrainingAppointment do
    OpenApiSpex.schema(%{
      title: "TrainingAppointment",
      description: "Request for a training appointment",
      type: :object,
      allOf: [
        AppointmentType,
        %Schema{
          type: :object,
          properties: %{
            level: %Schema{
              description: "The level of training",
              type: :integer
            }
          },
          required: [:level]
        }
      ]
    })
  end

  defmodule GroomingAppointment do
    OpenApiSpex.schema(%{
      title: "GroomingAppointment",
      description: "Request for a training appointment",
      type: :object,
      allOf: [
        AppointmentType,
        %Schema{
          type: :object,
          properties: %{
            hair_trim: %Schema{
              description: "Whether or not to include a hair trim",
              type: :boolean
            },
            nail_clip: %Schema{
              description: "Whether or not to include nail clip",
              type: :boolean
            }
          },
          required: [:hair_trim, :nail_clip]
        }
      ]
    })
  end

  defmodule PetAppointmentRequest do
    OpenApiSpex.schema(%{
      title: "PetAppointmentRequest",
      description: "POST body for making a pet appointment",
      type: :object,
      oneOf: [
        TrainingAppointment,
        GroomingAppointment
      ],
      discriminator: %OpenApiSpex.Discriminator{
        propertyName: "appointment_type",
        mapping: %{
          "training" => "TrainingAppointment",
          "grooming" => "GroomingAppointment"
        }
      }
    })
  end

@mbuhot
Copy link
Collaborator

mbuhot commented Nov 14, 2022

@Aduril Could you try the latest master branch commit? I've just pushed a change that resolves schema modules appearing in the discriminator mapping. #511

@Aduril
Copy link

Aduril commented Nov 14, 2022

@mbuhot It works great from my point of view:
image

Thansk for the quick fix! :)

@mbuhot
Copy link
Collaborator

mbuhot commented Nov 14, 2022

@Aduril Great I'll tag a release 👍

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

Successfully merging this pull request may close these issues.

7 participants