grape icon indicating copy to clipboard operation
grape copied to clipboard

"required" validators do not trigger for empty objects

Open marvinthepa opened this issue 6 years ago • 3 comments

        params do
          optional :foos, :type => Array do
            required :bar, :type => String
          end
        end

and then POSTing something like this:

{ "foos": [{}] }

Does not trigger validation, although the required :bar is missing.

I will try to at least submit a breaking test, or even a pull request.

marvinthepa avatar Feb 07 '19 11:02 marvinthepa

Looks like a big indeed. I bet we check for the class of whatever is inside the array. There's probably some other bugs like this with other types inside the array you might want to write specs for.

dblock avatar Feb 07 '19 16:02 dblock

/spec/grape/validations/params_scope_spec.rb

context 'when required param inside an optional is empty' do
    before do
      subject.params do
        optional :foos, type: Array do
          requires :bar, type: String
        end
      end
      subject.post('/required') { 'works' }

      post '/required', foos: [{}]
    end

    it 'returns an error' do
      expect(last_response.body).to eq('foos[0][bar] is missing')
      expect(last_response.status).to eq(400)
    end
  end

fails

Failures:

  1) Grape::Validations::ParamsScope when required param inside an optional is empty returns an error
     Failure/Error: expect(last_response.body).to eq('foos[0][bar] is missing')

       expected: "foos[0][bar] is missing"
            got: "works"

alexmamonchik avatar Jan 03 '20 09:01 alexmamonchik

This one is tricky.

First problem:

https://github.com/ruby-grape/grape/blob/62b9f6cc33adcd67e1a4654693fb07b06ca51305/lib/grape/validations/params_scope.rb#L50

If a scope (foos in this case) is empty and all children are empty too, the validation should be skipped.

Second problem:

https://github.com/ruby-grape/grape/blob/62b9f6cc33adcd67e1a4654693fb07b06ca51305/lib/grape/validations/validators/base.rb#L47

If a scope is optional (foos) and the value is empty, the validation should be skipped. Please note, the scope is only created for params wrapping other parameters. foos is a scope, bar is a parameter which has certain validations, its scope is the scope defined by foos.

If we remove these checks, we will start to require required params inside optional. This test is a perfect example:

https://github.com/ruby-grape/grape/blob/62b9f6cc33adcd67e1a4654693fb07b06ca51305/spec/grape/validations_spec.rb#L842-L850

After commenting out the mentioned lines, this test fails.

dnesteryuk avatar Jan 11 '20 17:01 dnesteryuk