jonasschmidt / ex_json_schema

An Elixir JSON Schema validator
MIT License
366 stars 98 forks source link

Validates an object as :ok when it does not match the provided schema #29

Closed Pilatch closed 6 years ago

Pilatch commented 6 years ago

What am I doing wrong here?

main.exs

defmodule Main do
  def main do

  schema = %{
      "type" => "object",
      "properties" => %{
        "foo" => %{
          "type" => "number"
        },
        "bar" => %{
          "type" => ["number", "null"]
        },
        "baz" => %{
          "type" => "string"
        },
      }
    } |> ExJsonSchema.Schema.resolve

    foo = Poison.decode!(~s({"whut": null, "tha": false, "hak": 455}))

    case ExJsonSchema.Validator.validate(schema, foo) do
      :ok -> foo |> inspect |> IO.puts
      # I can't get this thing to error out when I give it JSON that does not match the schema.
      {:err, messages} -> messages |> inspect |> IO.puts
    end
  end
end

Main.main

mix.exs

defmodule ElixirFoo.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixirFoo,
      version: "0.1.0",
      elixir: "~> 1.6-dev",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  def deps do
    [
      {:poison, "~> 3.1"},
      {:ex_json_schema, "~> 0.5.4"}
    ]
  end
end
jonasschmidt commented 6 years ago

By default, JSON Schema ignores properties that are not specified. You can change that behaviour by adding "additionalProperties" => false to your schema, then your example would fail. A more in-depth explanation of how objects and properties work can be found here: https://spacetelescope.github.io/understanding-json-schema/reference/object.html#properties

Pilatch commented 6 years ago

Found the problem. It errors out, which is the expected behavior, when you don't pipe. ExJsonSchema.Validator.validate(schema, foo) will produce the error messages, but foo |> ExJsonSchema.Validator.validate(schema) does not. This is probably because I misunderstand how Elixir handles partial function application.

bug_report.exs

defmodule Bug_Report do
  def main do

  schema = %{
      "type" => "object",
      "properties" => %{
        "foo" => %{
          "type" => "number"
        },
        "bar" => %{
          "type" => ["number", "null"]
        },
        "baz" => %{
          "type" => "string"
        },
      },
      "additionalProperties" => false
    } |> ExJsonSchema.Schema.resolve

    foo = %{
      "foo" => "Hello",
      "bar" => false,
      "baz" => 123
    }

    case ExJsonSchema.Validator.validate(schema, foo) do
      :ok -> foo |> inspect |> IO.puts
      # Even giving the validator an object with no fields that exist in the schema results in :ok.
      {:error, messages} -> messages |> inspect |> IO.puts
    end
  end
end

Bug_Report.main
jonasschmidt commented 6 years ago

Yeah, the |> operator is very specific, it passes the value on the left side as the first parameter to the function on the right side. In this case, it doesn't work unfortunately (actually I realized much later that the payload should be the first parameter to validate and the schema the second, but I didn't want to introduce that breaking change just to make things a bit more convenient).

Pilatch commented 6 years ago

Ah thanks. I'm coming from Elm, where we pipe to the last parameter.

jonasschmidt commented 6 years ago

👍