open-api-spex / open_api_spex

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

Schema oneOf among integer and string doesn't work with integer in a string ("1234") #578

Open davidjulien opened 7 months ago

davidjulien commented 7 months ago

Hi!

I would like to define a field id as an integer or a string. Thus I write this schema:

  OpenApiSpex.schema(%{
    oneOf: [
      %Schema{type: :integer},
      %Schema{type: :string}
    ]
  })

It works when my data is an integer 1234 or a string "my_id". But it doesn't work when it is an integer inside a string "1234". It triggers this error:

Value does not conform to schema:
Failed to cast value to one of: more than one schemas validate at .../id

I think that the reason is here. In the module Cast.Integer, we convert the value to integer when it is a binary containing an integer. Consequently, the two clauses of my oneOf are valid.

https://github.com/open-api-spex/open_api_spex/blob/531607c43f7b6ce3f10597b155afcb75f4ce2b1c/lib/open_api_spex/cast/integer.ex#L17-L22

Is there a workaround or can we remove this function clause?

I tried with anyOf instead of oneOf but in that case I have this error:

 ** (Protocol.UndefinedError) protocol Enumerable not implemented for 1234 of type Integer. This protocol is implemented for the following type(s): ...

Thank you

davidjulien commented 7 months ago

Here is a possible workaround:

  defmodule StrictIntegerValidation do
    @moduledoc """
    Ensure that we have really an integer, and not an integer inside a string
    """
    def cast(ctx) do
      if is_integer(ctx.value) do
        {:ok, ctx.value}
      else
        {:error, "Not strictly integer"}
      end
    end
  end

  OpenApiSpex.schema(%{
    oneOf: [
      %Schema{type: :string},
      %Schema{type: :integer, "x-validate": StrictIntegerValidation}
    ]
  })