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

How to require an Array param, disallow an empty array, but accept 'null' as a value #1198

Closed
mjpineyro opened this issue Nov 4, 2015 · 7 comments
Labels

Comments

@mjpineyro
Copy link

I have a validation like so:
requires :element, type: Array do

The only values that I want to accept in the JSON payload sent to the API are:
a) a non-empty array
b) the string 'null'

I can use allow_blank: false to disallow an empty array, but this validation also fires if null is sent.

How can I accept null, but not an empty array?

Why do I want this validation? Because we don't want to accept empty arrays as inputs, because these we believe can be ambiguous, i.e. did the developer/client really mean to send an empty array, or is the empty array the result of poor parsing or lack of proper validation on the client side? So if in fact there are no values to be sent for the array "element", we want that element to be set explicitly to null.

@dslh
Copy link
Contributor

dslh commented Nov 5, 2015

I'm not sure, but would this work?

ARRAY_OR_NULL = lambda do |val|
  if val == "null"
    nil
  elsif val.is_a?(Array) && !val.empty?
    val
  else
    fail ArgumentError
  end
end

# ...

requires :element, type: Array, coerce_with: ARRAY_OR_NULL do

Note that coerce_with is only on HEAD for the moment.

@dblock dblock added the discuss! label Nov 6, 2015
@mjpineyro
Copy link
Author

Thank you very much for your response. I tried implementing what you suggested, but I am not sure I had all the pieces in place. I was getting an error of the type `validate': unknown validator: array_or_null (Grape::Exceptions::UnknownValidator)

Based on the "Custom Validators" section in the documentation I have tried this:

Created this file under a 'validations' directory:

module V1

class NonEmptyArrayOrNull < Grape::Validations::Base
def validate_param!(attr_name, params)
val = params[attr_name]
unless val == 'null' || (val.is_a?(Array) && !val.empty?)
fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: 'maidCalls must contain a non-empty array, or null'
end
end
end

end

Then in my endpoint file I have:

module V1

class BlankGenotype < Grape::API
version 'v1', using: :path
prefix :api
format :json
default_format :json

require_relative 'custom_validations/non_empty_array_or_null'

...

begin
  params do

    requires :genotypeFather, type: Hash do
      requires :genotypeCanonical, type: Hash do
        requires :maidCalls, type: Array, non_empty_array_or_null: true do
          requires :maid, type: Integer, desc: "Maid ID"
        end

....

I get the following error:
NoMethodError (undefined method []' for nil:NilClass): app/api/v1/custom_validations/non_empty_array_or_null.rb:4:invalidate_param!'

Does this mean that the params parameter is not known to my custom validator class? How would I fix this?

@palpandiR
Copy link

I am having the same issue while using custom validation, the gem version is 0.13.0

@PHronek
Copy link

PHronek commented Feb 15, 2016

You simple need to upgrade to version 0.14.0. Theres no coerce_with property in 0.13.0.

@dblock
Copy link
Member

dblock commented Feb 15, 2016

👍 @PHronek I'm closing this, please reopen if the problem is different.

@dblock dblock closed this as completed Feb 15, 2016
@mjpineyro
Copy link
Author

I am not sure how to re-open this issue.

I am now using grape version 0.15.0, and I no longer get the NoMethodError (undefined method []' for nil:NilClass): error reported before.

Using the custom validation class that I created is working as expected, but the problem is that params[attr_name] in the NonEmptyArrayOrNull class is set to an empty array, both when the maidCalls element in the json payload is set to null and when it is set to an empty array. So using this custom validator, I still can't differentiate between the following 2 son inputs:

"maidCalls": null
"maidCalls": []

So it looks like Grape converts both of these inputs into an empty array when creating "params".

Is there a way of checking for null vs [], maybe params is defined?

@mjpineyro
Copy link
Author

Ah! but if I use this code, as originally suggested by dslh, it appears to work as I desire! In this case, it appears that val is set to whatever is sent in the json, instead of Grape converting it to an empty Array.

requires :maidCalls, type: Array, coerce_with: ->(val) { if val == "null"
nil
elsif val.is_a?(Array) && !val.empty?
val
else
fail ArgumentError
end }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants