Skip to content

Commit f5d7306

Browse files
Reynard Hilmandblock
Reynard Hilman
authored andcommitted
Add ability to use Grape::Entity documentation in the params block.
1 parent 3be5c01 commit f5d7306

File tree

4 files changed

+120
-7
lines changed

4 files changed

+120
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Next Release
1515
* [#544](https://github.com/intridea/grape/pull/544): The `rescue_from` keyword now handles subclasses of exceptions by default - [@xevix](https://github.com/xevix).
1616
* [#545](https://github.com/intridea/grape/pull/545): Added `type` (Array or Hash) support to `requires`, `optional` and `group` - [@bwalex](https://github.com/bwalex).
1717
* [#550](https://github.com/intridea/grape/pull/550): Added possibility to define reusable params - [@dm1try](https://github.com/dm1try).
18+
* [#560](https://github.com/intridea/grape/pull/560): Use `Grape::Entity` documentation to define required and optional parameters with `requires using:` - [@reynardmh](https://github.com/reynardmh).
1819
* Your contribution here.
1920

2021
#### Fixes

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,6 @@ The following example exposes statuses.
11691169

11701170
```ruby
11711171
module API
1172-
11731172
module Entities
11741173
class Status < Grape::Entity
11751174
expose :user_name
@@ -1196,6 +1195,23 @@ module API
11961195
end
11971196
```
11981197

1198+
You can use entity documentation directly in the params block with `using: Entity.documentation`.
1199+
1200+
```ruby
1201+
module API
1202+
class Statuses < Grape::API
1203+
version 'v1'
1204+
1205+
desc 'Create a status', {
1206+
requires :all, except: [:ip], using: API::Entities::Status.documentation.except(:id)
1207+
}
1208+
post '/status' do
1209+
Status.create! params
1210+
end
1211+
end
1212+
end
1213+
```
1214+
11991215
You can present with multiple entities using an optional Symbol argument.
12001216

12011217
```ruby

lib/grape/validations.rb

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,16 @@ def should_validate?(parameters)
108108
def requires(*attrs, &block)
109109
orig_attrs = attrs.clone
110110

111-
validations = { presence: true }
112-
validations.merge!(attrs.pop) if attrs.last.is_a?(Hash)
113-
validations[:type] ||= Array if block_given?
114-
validates(attrs, validations)
111+
opts = attrs.last.is_a?(Hash) ? attrs.pop : nil
115112

116-
block_given? ? new_scope(orig_attrs, &block) :
117-
push_declared_params(attrs)
113+
if opts && opts[:using]
114+
require_required_and_optional_fields(attrs.first, opts)
115+
else
116+
validate_attributes(attrs, opts, &block)
117+
118+
block_given? ? new_scope(orig_attrs, &block) :
119+
push_declared_params(attrs)
120+
end
118121
end
119122

120123
def optional(*attrs, &block)
@@ -172,6 +175,29 @@ def push_declared_params(attrs)
172175

173176
private
174177

178+
def require_required_and_optional_fields(context, opts)
179+
if context == :all
180+
optional_fields = opts[:except].is_a?(Array) ? opts[:except] : [opts[:except]].compact
181+
required_fields = opts[:using].keys - optional_fields
182+
else # attrs.first == :none
183+
required_fields = opts[:except].is_a?(Array) ? opts[:except] : [opts[:except]].compact
184+
optional_fields = opts[:using].keys - required_fields
185+
end
186+
required_fields.each do |field|
187+
requires(field, opts[:using][field])
188+
end
189+
optional_fields.each do |field|
190+
optional(field, opts[:using][field])
191+
end
192+
end
193+
194+
def validate_attributes(attrs, opts, &block)
195+
validations = { presence: true }
196+
validations.merge!(opts) if opts
197+
validations[:type] ||= Array if block
198+
validates(attrs, validations)
199+
end
200+
175201
def new_scope(attrs, optional = false, &block)
176202
opts = attrs[1] || { type: Array }
177203
raise ArgumentError unless opts.keys.to_set.subset? [:type].to_set

spec/grape/validations_spec.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,76 @@ def app
7878
end
7979
end
8080

81+
context 'requires :all using Grape::Entity documentation' do
82+
def define_requires_all
83+
documentation = {
84+
required_field: { type: String },
85+
optional_field: { type: String }
86+
}
87+
subject.params do
88+
requires :all, except: :optional_field, using: documentation
89+
end
90+
end
91+
before do
92+
define_requires_all
93+
subject.get '/required' do
94+
'required works'
95+
end
96+
end
97+
98+
it 'adds entity documentation to declared params' do
99+
define_requires_all
100+
subject.settings[:declared_params].should == [:required_field, :optional_field]
101+
end
102+
103+
it 'errors when required_field is not present' do
104+
get '/required'
105+
last_response.status.should == 400
106+
last_response.body.should == 'required_field is missing'
107+
end
108+
109+
it 'works when required_field is present' do
110+
get '/required', required_field: 'woof'
111+
last_response.status.should == 200
112+
last_response.body.should == 'required works'
113+
end
114+
end
115+
116+
context 'requires :none using Grape::Entity documentation' do
117+
def define_requires_none
118+
documentation = {
119+
required_field: { type: String },
120+
optional_field: { type: String }
121+
}
122+
subject.params do
123+
requires :none, except: :required_field, using: documentation
124+
end
125+
end
126+
before do
127+
define_requires_none
128+
subject.get '/required' do
129+
'required works'
130+
end
131+
end
132+
133+
it 'adds entity documentation to declared params' do
134+
define_requires_none
135+
subject.settings[:declared_params].should == [:required_field, :optional_field]
136+
end
137+
138+
it 'errors when required_field is not present' do
139+
get '/required'
140+
last_response.status.should == 400
141+
last_response.body.should == 'required_field is missing'
142+
end
143+
144+
it 'works when required_field is present' do
145+
get '/required', required_field: 'woof'
146+
last_response.status.should == 200
147+
last_response.body.should == 'required works'
148+
end
149+
end
150+
81151
context 'required with an Array block' do
82152
before do
83153
subject.params do

0 commit comments

Comments
 (0)