angus 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/lib/angus/base.rb +6 -3
- data/lib/angus/base_proxy.rb +20 -0
- data/lib/angus/base_resource.rb +8 -3
- data/lib/angus/generator/templates/definitions/operations.yml.erb +2 -0
- data/lib/angus/generator/templates/resources/resource.rb.erb +2 -2
- data/lib/angus/generator/thor/resource.rb +1 -1
- data/lib/angus/middleware/exception_handler.rb +2 -2
- data/lib/angus/request_handler.rb +7 -7
- data/lib/angus/rspec/support/examples.rb +3 -2
- data/lib/angus/rspec/support/examples/describe_errors.rb +23 -6
- data/lib/angus/utils/exceptions/invalid_parameter_type.rb +18 -0
- data/lib/angus/utils/exceptions/required_parameter_not_fond.rb +19 -0
- data/lib/angus/utils/params_validator.rb +81 -0
- data/spec/angus/middleware/exception_handler_spec.rb +16 -1
- data/spec/angus/rspec/examples/describe_errors_spec.rb +6 -0
- data/spec/functional/basic_spec.rb +2 -2
- data/spec/functional/empty_resource_spec.rb +2 -2
- data/spec/functional/no_resources_spec.rb +2 -2
- data/spec/functional/type_validation/definitions/admins/operations.yml +70 -0
- data/spec/functional/type_validation/definitions/messages.yml +0 -0
- data/spec/functional/type_validation/definitions/representations.yml +9 -0
- data/spec/functional/type_validation/definitions/service.yml +3 -0
- data/spec/functional/type_validation/models/admin.rb +1 -0
- data/spec/functional/type_validation/resources/admins.rb +35 -0
- data/spec/functional/type_validation/services/type_validation.rb +13 -0
- data/spec/functional/type_validation_spec.rb +283 -0
- data/spec/support/matchers/have_error_response_matcher.rb +40 -0
- data/spec/support/matchers/have_in_message_matcher.rb +47 -0
- data/spec/support/matchers/have_success_response_matcher.rb +40 -0
- metadata +95 -93
@@ -0,0 +1,70 @@
|
|
1
|
+
show:
|
2
|
+
name: Get information about a given user.
|
3
|
+
description: >
|
4
|
+
Returns all the information about a given user.
|
5
|
+
|
6
|
+
path: /admins/:id
|
7
|
+
method: get
|
8
|
+
uri:
|
9
|
+
- element: user_id
|
10
|
+
description: User identifier.
|
11
|
+
|
12
|
+
response:
|
13
|
+
- element: profile
|
14
|
+
description: User profile.
|
15
|
+
required: true
|
16
|
+
type: user
|
17
|
+
|
18
|
+
index:
|
19
|
+
name: Gets a list of users.
|
20
|
+
description: >
|
21
|
+
Returns all the information about all users.
|
22
|
+
|
23
|
+
path: /admins
|
24
|
+
method: get
|
25
|
+
request:
|
26
|
+
- element: requester_id
|
27
|
+
type: integer
|
28
|
+
required: true
|
29
|
+
description: User identifier.
|
30
|
+
|
31
|
+
response:
|
32
|
+
- element: users
|
33
|
+
description: Perfil del usuario
|
34
|
+
required: true
|
35
|
+
elements_type: user
|
36
|
+
|
37
|
+
create:
|
38
|
+
name: Create a user with the given parameters.
|
39
|
+
description: >
|
40
|
+
Returns the recently created user.
|
41
|
+
|
42
|
+
path: /admins
|
43
|
+
method: post
|
44
|
+
request:
|
45
|
+
- element: name
|
46
|
+
type: string
|
47
|
+
required: true
|
48
|
+
description: User name.
|
49
|
+
- element: age
|
50
|
+
type: integer
|
51
|
+
required: true
|
52
|
+
description: User age.
|
53
|
+
- element: favorite_decimal
|
54
|
+
type: decimal
|
55
|
+
required: true
|
56
|
+
description: User favorite decimal number.
|
57
|
+
- element: birth_date
|
58
|
+
type: date
|
59
|
+
required: true
|
60
|
+
description: The last time that the user signed in.
|
61
|
+
- element: last_signed_in_at
|
62
|
+
type: datetime
|
63
|
+
required: true
|
64
|
+
description: The last time that the user signed in.
|
65
|
+
|
66
|
+
response:
|
67
|
+
- element: user
|
68
|
+
description: Perfil del usuario
|
69
|
+
required: true
|
70
|
+
elements_type: user
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
Admin = Struct.new(:id, :name, :age)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../models/admin'
|
2
|
+
|
3
|
+
|
4
|
+
class Admins < Angus::BaseResource
|
5
|
+
|
6
|
+
ADMINS = [
|
7
|
+
Admin.new(1, 'John Smith', 33),
|
8
|
+
Admin.new(2, 'John Doe', 44)
|
9
|
+
]
|
10
|
+
|
11
|
+
def show
|
12
|
+
user = ADMINS.find { |user| user[:id] == params[:id].to_i }
|
13
|
+
|
14
|
+
{:profile => user}
|
15
|
+
end
|
16
|
+
|
17
|
+
def index
|
18
|
+
{ :users => ADMINS }
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
user = Admin.new(last_id, params[:name], params[:age])
|
23
|
+
|
24
|
+
{ :user => user }
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# This is not a good practice is only for testing propose. Use an
|
30
|
+
# autogenerated id (using db features).
|
31
|
+
def last_id
|
32
|
+
ADMINS.map {|user| user['id'] }.max + 1
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'functional/type_validation/services/type_validation'
|
4
|
+
|
5
|
+
working_dir = "#{File.dirname(__FILE__ )}/type_validation"
|
6
|
+
|
7
|
+
describe Spec::Functional::TypeValidation, { :work_dir => working_dir } do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
|
10
|
+
subject(:app) { Rack::Lint.new(Spec::Functional::TypeValidation.new) }
|
11
|
+
|
12
|
+
describe 'required fields validation' do
|
13
|
+
it 'responds correctly if all required fields are given' do
|
14
|
+
get '/type_validation/api/0.1/admins?requester_id=1'
|
15
|
+
|
16
|
+
response = JSON(last_response.body)
|
17
|
+
|
18
|
+
expect(response['status']).to eq('success')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'responds with an error when a required field is not present' do
|
22
|
+
get '/type_validation/api/0.1/admins'
|
23
|
+
|
24
|
+
expect(last_response).to have_error_response
|
25
|
+
expect(last_response).to have_in_message({
|
26
|
+
'level' => 'error',
|
27
|
+
'key' => 'TODO define',
|
28
|
+
'dsc' => 'requester_id'
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'type fields validation' do
|
34
|
+
let(:valid_params) {
|
35
|
+
{
|
36
|
+
'name' => 'Britney Watson',
|
37
|
+
'age' => 22,
|
38
|
+
'favorite_decimal' => 21.3,
|
39
|
+
'birth_date' => Date.today.iso8601,
|
40
|
+
'last_signed_in_at' => DateTime.now.iso8601
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
context 'string type' do
|
45
|
+
it 'should be valid if a number is given' do
|
46
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
47
|
+
'name' => 22
|
48
|
+
})
|
49
|
+
|
50
|
+
expect(last_response).to have_success_response
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should be valid if a text is given' do
|
54
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
55
|
+
'name' => 'Example Text'
|
56
|
+
})
|
57
|
+
|
58
|
+
expect(last_response).to have_success_response
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should be valid if a date is given' do
|
62
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
63
|
+
'name' => Date.today
|
64
|
+
})
|
65
|
+
|
66
|
+
expect(last_response).to have_success_response
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'integer type' do
|
71
|
+
it 'should be valid if a number is given' do
|
72
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
73
|
+
'age' => 22
|
74
|
+
})
|
75
|
+
|
76
|
+
expect(last_response).to have_success_response
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should not be valid if a decimal is given' do
|
80
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
81
|
+
'age' => 22.1
|
82
|
+
})
|
83
|
+
|
84
|
+
expect(last_response).to have_error_response
|
85
|
+
expect(last_response).to have_in_message({
|
86
|
+
'level' => 'error',
|
87
|
+
'key' => 'TODO define',
|
88
|
+
'dsc' => 'TODO define'
|
89
|
+
})
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should not be valid if a text is given' do
|
93
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
94
|
+
'age' => 'Example Text'
|
95
|
+
})
|
96
|
+
|
97
|
+
expect(last_response).to have_error_response
|
98
|
+
expect(last_response).to have_in_message({
|
99
|
+
'level' => 'error',
|
100
|
+
'key' => 'TODO define',
|
101
|
+
'dsc' => 'TODO define'
|
102
|
+
})
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should not be valid if a date is given' do
|
106
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
107
|
+
'age' => Date.today
|
108
|
+
})
|
109
|
+
|
110
|
+
expect(last_response).to have_error_response
|
111
|
+
expect(last_response).to have_in_message({
|
112
|
+
'level' => 'error',
|
113
|
+
'key' => 'TODO define',
|
114
|
+
'dsc' => 'TODO define'
|
115
|
+
})
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'decimal type' do
|
120
|
+
it 'should be valid if a number is given' do
|
121
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
122
|
+
'favorite_decimal' => 22
|
123
|
+
})
|
124
|
+
|
125
|
+
expect(last_response).to have_success_response
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should be valid if a decimal is given' do
|
129
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
130
|
+
'favorite_decimal' => 22.1
|
131
|
+
})
|
132
|
+
|
133
|
+
expect(last_response).to have_success_response
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should not be valid if a text is given' do
|
137
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
138
|
+
'favorite_decimal' => 'Example Text'
|
139
|
+
})
|
140
|
+
|
141
|
+
expect(last_response).to have_error_response
|
142
|
+
expect(last_response).to have_in_message({
|
143
|
+
'level' => 'error',
|
144
|
+
'key' => 'TODO define',
|
145
|
+
'dsc' => 'TODO define'
|
146
|
+
})
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should not be valid if a date is given' do
|
150
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
151
|
+
'favorite_decimal' => Date.today
|
152
|
+
})
|
153
|
+
|
154
|
+
expect(last_response).to have_error_response
|
155
|
+
expect(last_response).to have_in_message({
|
156
|
+
'level' => 'error',
|
157
|
+
'key' => 'TODO define',
|
158
|
+
'dsc' => 'TODO define'
|
159
|
+
})
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'date type' do
|
164
|
+
it 'should be valid if a number is given' do
|
165
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
166
|
+
'birth_date' => 22
|
167
|
+
})
|
168
|
+
|
169
|
+
expect(last_response).to have_error_response
|
170
|
+
expect(last_response).to have_in_message({
|
171
|
+
'level' => 'error',
|
172
|
+
'key' => 'TODO define',
|
173
|
+
'dsc' => 'TODO define'
|
174
|
+
})
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should be valid if a decimal is given' do
|
178
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
179
|
+
'birth_date' => 22.1
|
180
|
+
})
|
181
|
+
|
182
|
+
expect(last_response).to have_error_response
|
183
|
+
expect(last_response).to have_in_message({
|
184
|
+
'level' => 'error',
|
185
|
+
'key' => 'TODO define',
|
186
|
+
'dsc' => 'TODO define'
|
187
|
+
})
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should not be valid if a text is given' do
|
191
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
192
|
+
'birth_date' => 'Example Text'
|
193
|
+
})
|
194
|
+
|
195
|
+
expect(last_response).to have_error_response
|
196
|
+
expect(last_response).to have_in_message({
|
197
|
+
'level' => 'error',
|
198
|
+
'key' => 'TODO define',
|
199
|
+
'dsc' => 'TODO define'
|
200
|
+
})
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should be valid if a date is given' do
|
204
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
205
|
+
'birth_date' => Date.today.iso8601
|
206
|
+
})
|
207
|
+
|
208
|
+
expect(last_response).to have_success_response
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should not be valid if a date is given' do
|
212
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
213
|
+
'birth_date' => DateTime.now.iso8601
|
214
|
+
})
|
215
|
+
|
216
|
+
expect(last_response).to have_success_response
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'datetime type' do
|
221
|
+
it 'should be valid if a number is given' do
|
222
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
223
|
+
'last_signed_in_at' => 22
|
224
|
+
})
|
225
|
+
|
226
|
+
expect(last_response).to have_error_response
|
227
|
+
expect(last_response).to have_in_message({
|
228
|
+
'level' => 'error',
|
229
|
+
'key' => 'TODO define',
|
230
|
+
'dsc' => 'TODO define'
|
231
|
+
})
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'should be valid if a decimal is given' do
|
235
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
236
|
+
'last_signed_in_at' => 22.1
|
237
|
+
})
|
238
|
+
|
239
|
+
expect(last_response).to have_error_response
|
240
|
+
expect(last_response).to have_in_message({
|
241
|
+
'level' => 'error',
|
242
|
+
'key' => 'TODO define',
|
243
|
+
'dsc' => 'TODO define'
|
244
|
+
})
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'should not be valid if a text is given' do
|
248
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
249
|
+
'last_signed_in_at' => 'Example Text'
|
250
|
+
})
|
251
|
+
|
252
|
+
expect(last_response).to have_error_response
|
253
|
+
expect(last_response).to have_in_message({
|
254
|
+
'level' => 'error',
|
255
|
+
'key' => 'TODO define',
|
256
|
+
'dsc' => 'TODO define'
|
257
|
+
})
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should not be valid if a date is given' do
|
261
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
262
|
+
'last_signed_in_at' => Date.today.iso8601
|
263
|
+
})
|
264
|
+
|
265
|
+
expect(last_response).to have_error_response
|
266
|
+
expect(last_response).to have_in_message({
|
267
|
+
'level' => 'error',
|
268
|
+
'key' => 'TODO define',
|
269
|
+
'dsc' => 'TODO define'
|
270
|
+
})
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should not be valid if a date is given' do
|
274
|
+
post '/type_validation/api/0.1/admins', valid_params.merge({
|
275
|
+
'last_signed_in_at' => DateTime.now.iso8601
|
276
|
+
})
|
277
|
+
|
278
|
+
expect(last_response).to have_success_response
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
RSpec::Matchers.define :have_error_response do
|
2
|
+
|
3
|
+
match do |response|
|
4
|
+
begin
|
5
|
+
@json = JSON(response.body)
|
6
|
+
|
7
|
+
is_valid_response?
|
8
|
+
rescue JSON::ParserError => exception
|
9
|
+
@error = "Error will parsing response: #{exception.message}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
description do
|
14
|
+
'have error response'
|
15
|
+
end
|
16
|
+
|
17
|
+
failure_message_for_should do
|
18
|
+
if @error
|
19
|
+
@error
|
20
|
+
elsif @json && @json['status']
|
21
|
+
"expect #{@json['status']} to be error\n#{@json.inspect}"
|
22
|
+
else
|
23
|
+
"expect #{@json} to include status in it's keys"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
failure_message_for_should_not do
|
28
|
+
if @error
|
29
|
+
@error
|
30
|
+
elsif @json && @json['status']
|
31
|
+
"expect #{@json['status']} to not be error\n#{@json.inspect}"
|
32
|
+
else
|
33
|
+
"expect #{@json} to include status in it's keys"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_valid_response?
|
38
|
+
@json && @json['status'] == 'error'
|
39
|
+
end
|
40
|
+
end
|