Skip to content

add ability to use Grape::Entity documentation in the params block #560

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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Next Release
* [#544](https://github.com/intridea/grape/pull/544): The `rescue_from` keyword now handles subclasses of exceptions by default - [@xevix](https://github.com/xevix).
* [#545](https://github.com/intridea/grape/pull/545): Added `type` (Array or Hash) support to `requires`, `optional` and `group` - [@bwalex](https://github.com/bwalex).
* [#550](https://github.com/intridea/grape/pull/550): Added possibility to define reusable params - [@dm1try](https://github.com/dm1try).
* [#560](https://github.com/intridea/grape/pull/560): Added ability to use Grape::Entity documentation in the params block - [@reynardmh](https://github.com/reynardmh).
* Your contribution here.

#### Fixes
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,27 @@ module API
end
```

You can use entity documentation in the params block
```ruby
class User::Entity < Grape::Entity
expose :id, documentation: { type: Integer}
expose :name, documentation: { type: String, desc: "Name" }
expose :email, documentation: { type: String, desc: "Email address" }
end

class Users < Grape::API
desc 'Create user'
params do
requires :all, except: [:name], using: User::Entity.documentation.except(:id)
end
post 'users' do
# implement create user
end
end

```


You can present with multiple entities using an optional Symbol argument.

```ruby
Expand Down
33 changes: 27 additions & 6 deletions lib/grape/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,18 @@ def should_validate?(parameters)
def requires(*attrs, &block)
orig_attrs = attrs.clone

validations = { presence: true }
validations.merge!(attrs.pop) if attrs.last.is_a?(Hash)
validations[:type] ||= Array if block_given?
validates(attrs, validations)
opts = attrs.last.is_a?(Hash) ? attrs.pop : nil
if opts && opts[:using]
requires_using_entity_doc(attrs.first, opts)
else
validations = { presence: true }
validations.merge!(opts) if opts
validations[:type] ||= Array if block_given?
validates(attrs, validations)

block_given? ? new_scope(orig_attrs, &block) :
push_declared_params(attrs)
block_given? ? new_scope(orig_attrs, &block) :
push_declared_params(attrs)
end
end

def optional(*attrs, &block)
Expand Down Expand Up @@ -172,6 +177,22 @@ def push_declared_params(attrs)

private

def requires_using_entity_doc(mode, opts)
if mode == :all
optional_fields = Array(opts[:except])
required_fields = opts[:using].keys - optional_fields
else # mode == :none
required_fields = Array(opts[:except])
optional_fields = opts[:using].keys - required_fields
end
required_fields.each do |field|
requires(field, opts[:using][field])
end
optional_fields.each do |field|
optional(field, opts[:using][field])
end
end

def new_scope(attrs, optional = false, &block)
opts = attrs[1] || { type: Array }
raise ArgumentError unless opts.keys.to_set.subset? [:type].to_set
Expand Down
70 changes: 70 additions & 0 deletions spec/grape/validations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,76 @@ def app
end
end

context 'requires :all using Grape::Entity documentation' do
def define_requires_all
documentation = {
required_field: { type: String },
optional_field: { type: String }
}
subject.params do
requires :all, except: :optional_field, using: documentation
end
end
before do
define_requires_all
subject.get '/required' do
'required works'
end
end

it 'adds entity documentation to declared params' do
define_requires_all
subject.settings[:declared_params].should == [:required_field, :optional_field]
end

it 'errors when required_field is not present' do
get '/required'
last_response.status.should == 400
last_response.body.should == 'required_field is missing'
end

it 'works when required_field is present' do
get '/required', required_field: 'woof'
last_response.status.should == 200
last_response.body.should == 'required works'
end
end

context 'requires :none using Grape::Entity documentation' do
def define_requires_none
documentation = {
required_field: { type: String },
optional_field: { type: String }
}
subject.params do
requires :none, except: :required_field, using: documentation
end
end
before do
define_requires_none
subject.get '/required' do
'required works'
end
end

it 'adds entity documentation to declared params' do
define_requires_none
subject.settings[:declared_params].should == [:required_field, :optional_field]
end

it 'errors when required_field is not present' do
get '/required'
last_response.status.should == 400
last_response.body.should == 'required_field is missing'
end

it 'works when required_field is present' do
get '/required', required_field: 'woof'
last_response.status.should == 200
last_response.body.should == 'required works'
end
end

context 'required with an Array block' do
before do
subject.params do
Expand Down