问题
How do I write the correct params
validations for this hash parameter:
{
"files": {
"main.c": {
"contents": "#include <stdio.h> ...",
"foo": "bar"
},
"main.h": {
"contents": "#define BLAH ...",
"foo": "baz"
},
... more files here ...
}
}
files
is the hash parameter that I want to validate. Each key of files
can be anything (a string); the values are hashes with a specific format that also needs to be validated (requires contents
and foo
). I'm using grape 0.9.0.
This is kind of what I want to have:
params do
optional :files, type: Hash do
requires <any key>, type: Hash do
requires :contents, type: String
requires :foo, type: String
end
end
end
I've read the documentation but I couldn't see how to achieve this kind of validation. Is it even possible? Do I need to write a custom validator?
An alternative is to have this instead:
{
"files":
[
{
"name": "main.c",
"contents": "#include <stdio.h> ...",
"foo": "bar"
},
{
"name": "main.h",
"contents": "#define BLAH ...",
"foo": "baz"
}
]
}
which can be easily validated like this:
params do
optional :files, type: Array do
requires :name, type: String
requires :contents, type: String
requires :foo, type: String
end
end
but now I lose the ability to have unique file names.
回答1:
Based on the grape documentation I would come up with the idea of writing your own custom validator and go with your second alternative.
class UniqueHashAttributes < Grape::Validations::Base
def validate_param!(attr_name, params)
# assuming @option is an array
@option.each do |attribute|
# detects if the value of the attribute is found more than once
if params[attr_name].group_by { |h| h[attribute] }.values.collect(&:size).max > 1
fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
message: "must have only unique values for properties: '#{@option.join(', ')}'"
end
end
end
end
It would also be possible to report custom errors that present the uniqueness violations. Of course this principle can also be applied to perform different kind of validations than the uniqueness.
If this validator is loaded in your application, you can utilize it in your params
definition of the route as follows:
params do
optional :files, unique_hash_attributes: [:name], type: Array do
requires :name, type: String
requires :contents, type: String
requires :foo, type: String
end
end
post '/validation' do
'passed'
end
With this implementation you could also specify the :foo
field (or any other) to be unique by adding it to the array of the unique hash attributes.
Any validations of the Hash's values (name, contents, foo) remain unchanged of the files
validator and still apply.
A post request with the following data would not pass the verification:
{ "files":
[
{
"name": "main.c",
"contents": "#include <stdio.h> ...",
"foo": "bar"
},
{
"name": "main.c",
"contents": "#define BLAH ...",
"foo": "baz"
}
]
}
来源:https://stackoverflow.com/questions/27728326/how-to-validate-this-hash-parameter