angus 0.0.3 → 0.0.4
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.
- data/lib/angus/base.rb +42 -29
- data/lib/angus/base_actions.rb +12 -6
- data/lib/angus/definition_reader.rb +19 -0
- data/lib/angus/generator/templates/config.ru.erb +1 -1
- data/lib/angus/generator.rb +7 -7
- data/lib/angus/middleware/exception_handler.rb +130 -0
- data/lib/angus/renders/json_render.rb +9 -7
- data/lib/angus/request_handler.rb +32 -24
- data/lib/angus/responses.rb +3 -39
- data/lib/angus/status_codes.rb +23 -0
- data/lib/angus/version.rb +1 -1
- data/spec/angus/middleware/exception_handler_spec.rb +63 -0
- data/spec/functional/basic/definitions/messages.yml +2 -2
- data/spec/functional/basic/definitions/representations.yml +1 -2
- data/spec/functional/basic/definitions/users/operations.yml +2 -6
- data/spec/functional/basic/exceptions/user_errors.rb +9 -0
- data/spec/functional/basic/resources/users.rb +10 -4
- data/spec/functional/basic/services/basic.rb +0 -1
- data/spec/functional/basic_spec.rb +25 -2
- data/spec/functional/empty_resource/services/empty_resource.rb +0 -1
- data/spec/functional/empty_resource_spec.rb +2 -2
- data/spec/functional/no_resources/services/no_resources.rb +1 -3
- data/spec/functional/no_resources_spec.rb +2 -2
- data/spec/spec_helper.rb +10 -0
- metadata +11 -4
data/lib/angus/base.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative 'responses'
|
|
9
9
|
require_relative 'renders/base'
|
10
10
|
require_relative 'marshallings/base'
|
11
11
|
require_relative 'base_actions'
|
12
|
+
require_relative 'definition_reader'
|
12
13
|
|
13
14
|
require 'angus/sdoc'
|
14
15
|
|
@@ -18,15 +19,22 @@ module Angus
|
|
18
19
|
|
19
20
|
FIRST_VERSION = '0.1'
|
20
21
|
|
22
|
+
PRODUCTION_ENV = :production
|
23
|
+
DEVELOPMENT_ENV = :development
|
24
|
+
TEST_ENV = :test
|
25
|
+
DEFAULT_ENV = DEVELOPMENT_ENV
|
26
|
+
|
27
|
+
attr_reader :definitions
|
28
|
+
|
21
29
|
def initialize
|
22
30
|
super
|
23
31
|
|
24
|
-
@resources_definitions
|
25
|
-
@version
|
26
|
-
@name
|
27
|
-
@configured
|
28
|
-
@definitions
|
29
|
-
@logger
|
32
|
+
@resources_definitions = []
|
33
|
+
@version = FIRST_VERSION
|
34
|
+
@name = self.class.name.downcase
|
35
|
+
@configured = false
|
36
|
+
@definitions = nil
|
37
|
+
@logger = Logger.new(STDOUT)
|
30
38
|
|
31
39
|
configure!
|
32
40
|
|
@@ -40,18 +48,33 @@ module Angus
|
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
51
|
+
def production?
|
52
|
+
environment_name.to_sym == PRODUCTION_ENV
|
53
|
+
end
|
54
|
+
|
55
|
+
def development?
|
56
|
+
environment_name.to_sym == DEVELOPMENT_ENV
|
57
|
+
end
|
58
|
+
|
59
|
+
def test?
|
60
|
+
environment_name.to_sym == TEST_ENV
|
61
|
+
end
|
62
|
+
|
63
|
+
def environment_name
|
64
|
+
ENV['RACK_ENV'] || DEFAULT_ENV
|
65
|
+
end
|
66
|
+
|
43
67
|
def configured?
|
44
68
|
@configured
|
45
69
|
end
|
46
70
|
|
47
|
-
# TODO ver que hacer
|
48
71
|
def configure
|
72
|
+
warn 'Empty configuration for service.'
|
49
73
|
end
|
50
74
|
|
51
75
|
def configure!
|
52
76
|
raise 'Already configured' if configured?
|
53
77
|
|
54
|
-
# TODO ver como hacer configurable
|
55
78
|
@definitions = Angus::SDoc::DefinitionsReader.service_definition('definitions')
|
56
79
|
|
57
80
|
configure
|
@@ -79,42 +102,32 @@ module Angus
|
|
79
102
|
|
80
103
|
def register_resource_routes(resource_definition)
|
81
104
|
resource_definition.operations.each do |operation|
|
82
|
-
method = operation.
|
105
|
+
method = operation.http_method.to_sym
|
83
106
|
op_path = "#{api_path}#{operation.path}"
|
84
107
|
|
85
108
|
response_metadata = resource_definition.build_response_metadata(operation.response_elements)
|
86
109
|
|
87
110
|
router.on(method, op_path) do |env, params|
|
88
111
|
request = Rack::Request.new(env)
|
89
|
-
params
|
112
|
+
params = Params.indifferent_params(params)
|
113
|
+
response = Response.new
|
90
114
|
|
91
115
|
resource = resource_definition.resource_class.new(request, params)
|
92
|
-
|
93
|
-
|
94
|
-
begin
|
95
|
-
response = resource.send(operation.code_name)
|
116
|
+
response['Content-Type'] = 'application/json'
|
96
117
|
|
97
|
-
|
118
|
+
op_response = resource.send(operation.code_name)
|
119
|
+
op_response = {} unless op_response.is_a?(Hash)
|
98
120
|
|
99
|
-
|
121
|
+
messages = op_response.delete(:messages)
|
100
122
|
|
101
|
-
|
123
|
+
op_response = build_data_response(op_response, response_metadata, messages)
|
102
124
|
|
103
|
-
|
104
|
-
rescue Exception => error
|
105
|
-
status_code = get_error_status_code(error)
|
106
|
-
if status_code == Angus::Responses::HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR
|
107
|
-
@logger.error("An exception occurs on #{resource.class.name}##{operation.code_name}")
|
108
|
-
@logger.error(error)
|
109
|
-
end
|
110
|
-
response = build_error_response(error)
|
125
|
+
response.write(op_response)
|
111
126
|
|
112
|
-
|
113
|
-
@response.write(response)
|
114
|
-
end
|
127
|
+
response
|
115
128
|
end
|
116
129
|
end
|
117
130
|
end
|
118
131
|
|
119
132
|
end
|
120
|
-
end
|
133
|
+
end
|
data/lib/angus/base_actions.rb
CHANGED
@@ -9,19 +9,25 @@ module Angus
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def register_base_routes
|
12
|
-
router.on(:get, '/') do
|
13
|
-
|
12
|
+
router.on(:get, '/') do |env, params|
|
13
|
+
response = Response.new
|
14
|
+
|
15
|
+
render(response, discover_paths)
|
14
16
|
end
|
15
17
|
|
16
|
-
router.on(:get, base_path) do
|
17
|
-
|
18
|
+
router.on(:get, base_path) do |env, params|
|
19
|
+
response = Response.new
|
20
|
+
|
21
|
+
render(response, discover_paths)
|
18
22
|
end
|
19
23
|
|
20
24
|
router.on(:get, doc_path) do |env, params|
|
25
|
+
response = Response.new
|
26
|
+
|
21
27
|
if params[:format] == 'json'
|
22
|
-
render(Angus::SDoc::JsonFormatter.format_service(@definitions), format: :json)
|
28
|
+
render(response, Angus::SDoc::JsonFormatter.format_service(@definitions), format: :json)
|
23
29
|
else
|
24
|
-
render(Angus::SDoc::HtmlFormatter.format_service(@definitions), format: :html)
|
30
|
+
render(response, Angus::SDoc::HtmlFormatter.format_service(@definitions), format: :html)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Angus
|
2
|
+
class DefinitionReader
|
3
|
+
|
4
|
+
attr_reader :definitions
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@definitions = SDoc::DefinitionsReader.service_definition('definitions')
|
8
|
+
end
|
9
|
+
|
10
|
+
def message_definition(key, level)
|
11
|
+
message = definitions.messages.find { |name, definition|
|
12
|
+
name == key.to_s && definition.level.downcase == level.downcase
|
13
|
+
}
|
14
|
+
|
15
|
+
message.last if message
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/angus/generator.rb
CHANGED
@@ -13,13 +13,13 @@ module Angus
|
|
13
13
|
NEW_APP_DIRECTORIES = %W(#{DEFINITIONS_DIR} #{RESOURCES_DIR} #{SERVICES_DIR})
|
14
14
|
|
15
15
|
NEW_APP_FILES = %w(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
Gemfile
|
17
|
+
config.ru.erb
|
18
|
+
services/service.rb.erb
|
19
|
+
definitions/messages.yml
|
20
|
+
definitions/representations.yml
|
21
|
+
definitions/service.yml.erb
|
22
|
+
)
|
23
23
|
|
24
24
|
FILE_MAPPINGS = {
|
25
25
|
'services/service.rb.erb' => -> command, app_name { File.join(SERVICES_DIR, "#{command.underscore(command.classify(app_name))}.rb") },
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require_relative '../definition_reader'
|
2
|
+
require_relative '../responses'
|
3
|
+
require_relative '../status_codes'
|
4
|
+
require_relative '../../../lib/angus/renders/json_render'
|
5
|
+
|
6
|
+
module Angus
|
7
|
+
module Middleware
|
8
|
+
class ExceptionHandler
|
9
|
+
include Angus::StatusCodes
|
10
|
+
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
@definition_reader = Angus::DefinitionReader.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
dup.call!(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call!(env)
|
21
|
+
@app.call(env)
|
22
|
+
rescue Exception => exception
|
23
|
+
[
|
24
|
+
status_code(exception),
|
25
|
+
{ 'Content-Type' => 'application/json' },
|
26
|
+
[build_error_response(exception)]
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
|
33
|
+
# Builds a service error response
|
34
|
+
def build_error_response(error)
|
35
|
+
error_messages = messages_from_error(error)
|
36
|
+
|
37
|
+
JsonRender.convert(:status => :error, :messages => error_messages)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Returns an array of messages errors to be sent in an operation response
|
42
|
+
#
|
43
|
+
# If {error} respond_to? :errors then the method returns one error message
|
44
|
+
# for each one.
|
45
|
+
#
|
46
|
+
# Each message returned is a hash with:
|
47
|
+
# - level
|
48
|
+
# - key
|
49
|
+
# - description
|
50
|
+
#
|
51
|
+
# @param [Exception] error The error to be returned
|
52
|
+
#
|
53
|
+
# @return [Array] an array of messages
|
54
|
+
def messages_from_error(error, level = :error)
|
55
|
+
messages = []
|
56
|
+
|
57
|
+
if error.respond_to?(:errors)
|
58
|
+
error.errors.each do |key, description|
|
59
|
+
messages << {:level => level, :key => key, :dsc => description}
|
60
|
+
end
|
61
|
+
elsif error.respond_to?(:error_key)
|
62
|
+
messages << {:level => level, :key => error.error_key,
|
63
|
+
:dsc => error_message(error)}
|
64
|
+
else
|
65
|
+
messages << {:level => level, :key => error.class.name, :dsc => error.message}
|
66
|
+
end
|
67
|
+
|
68
|
+
messages
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Returns the message for an error.
|
73
|
+
#
|
74
|
+
# It first tries to get the message from text attribute of the error definition
|
75
|
+
# if no definition is found or if the text attribute is blank it the returns the error
|
76
|
+
# message attribute.
|
77
|
+
#
|
78
|
+
# @param [Exception] error The error to get the message for.
|
79
|
+
#
|
80
|
+
# @return [String] the error message.
|
81
|
+
def error_message(error)
|
82
|
+
error_definition = error_definition(error)
|
83
|
+
|
84
|
+
if error_definition && !error_definition.text.blank?
|
85
|
+
error_definition.text
|
86
|
+
else
|
87
|
+
error.message
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the error definition.
|
92
|
+
#
|
93
|
+
# If the error does not responds to error_key nil will be returned, see EvolutionError.
|
94
|
+
#
|
95
|
+
# @param [#error_key] error An error object
|
96
|
+
#
|
97
|
+
# @return [Hash]
|
98
|
+
def error_definition(error)
|
99
|
+
error_key = error.class.name
|
100
|
+
|
101
|
+
@definition_reader.message_definition(error_key, SDoc::Definitions::Message::ERROR_LEVEL)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns a suitable HTTP status code for the given error
|
105
|
+
#
|
106
|
+
# If error param responds to #errors, then #{HTTP_STATUS_CODE_CONFLICT} will be returned.
|
107
|
+
#
|
108
|
+
# If error param responds to #error_key, then the status_code associated
|
109
|
+
# with the message will be returned.
|
110
|
+
#
|
111
|
+
# @param [#errors, #error_key] exception An error object
|
112
|
+
#
|
113
|
+
# @return [Integer] HTTP status code
|
114
|
+
def status_code(exception)
|
115
|
+
if exception.respond_to?(:errors)
|
116
|
+
return HTTP_STATUS_CODE_CONFLICT
|
117
|
+
end
|
118
|
+
|
119
|
+
message = error_definition(exception)
|
120
|
+
|
121
|
+
if message
|
122
|
+
message.status_code
|
123
|
+
else
|
124
|
+
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module JsonRender
|
2
2
|
|
3
|
+
def self.convert(json)
|
4
|
+
if json.is_a?(String)
|
5
|
+
json
|
6
|
+
else
|
7
|
+
JSON(json, :ascii_only => true)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
3
11
|
def self.render(response, json)
|
4
12
|
response['Content-Type'] = 'application/json'
|
5
13
|
|
6
|
-
|
7
|
-
json
|
8
|
-
else
|
9
|
-
JSON(json, :ascii_only => true)
|
10
|
-
end
|
11
|
-
|
12
|
-
response.write(json)
|
14
|
+
response.write(convert(json))
|
13
15
|
end
|
14
16
|
|
15
17
|
end
|
@@ -2,6 +2,7 @@ require 'angus-router'
|
|
2
2
|
|
3
3
|
require_relative 'response'
|
4
4
|
require_relative 'responses'
|
5
|
+
require_relative 'middleware/exception_handler'
|
5
6
|
|
6
7
|
module Angus
|
7
8
|
class RequestHandler
|
@@ -10,10 +11,11 @@ module Angus
|
|
10
11
|
|
11
12
|
DEFAULT_RENDER = :json
|
12
13
|
|
13
|
-
attr_reader :env, :request, :response, :params
|
14
|
-
|
15
14
|
def initialize
|
16
15
|
@router = Angus::Router.new
|
16
|
+
@middleware = []
|
17
|
+
|
18
|
+
use Middleware::ExceptionHandler
|
17
19
|
end
|
18
20
|
|
19
21
|
def router
|
@@ -21,41 +23,47 @@ module Angus
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def call(env)
|
24
|
-
|
25
|
-
|
26
|
-
@response = Response.new
|
26
|
+
to_app.call(env)
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def to_app
|
30
|
+
inner_app = lambda { |env| self.dup.call!(env) }
|
31
|
+
@middleware.reverse.inject(inner_app) { |app, middleware| middleware.call(app) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def call!(env)
|
35
|
+
begin
|
36
|
+
response = router.route(env)
|
37
|
+
rescue NotImplementedError
|
38
|
+
response = Response.new
|
39
|
+
response.status = HTTP_STATUS_CODE_NOT_FOUND
|
31
40
|
|
32
|
-
render({ 'status' => 'error',
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
render(response, { 'status' => 'error',
|
42
|
+
'messages' => [{ 'level' => 'error', 'key' => 'RouteNotFound',
|
43
|
+
'dsc' => 'Invalid route' }]
|
44
|
+
}, {format: :json})
|
36
45
|
end
|
37
46
|
|
38
|
-
|
47
|
+
response.finish
|
39
48
|
end
|
40
49
|
|
41
50
|
# TODO ver multiples formatos en el futuro
|
42
|
-
def render(content, options = {})
|
51
|
+
def render(response, content, options = {})
|
43
52
|
format = options[:format] || DEFAULT_RENDER
|
44
53
|
case(format)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
54
|
+
when :html
|
55
|
+
HtmlRender.render(response, content)
|
56
|
+
when :json
|
57
|
+
JsonRender.render(response, content)
|
58
|
+
else
|
59
|
+
raise 'Unknown render format'
|
51
60
|
end
|
61
|
+
|
62
|
+
response
|
52
63
|
end
|
53
64
|
|
54
|
-
# TODO ver esto en el futuro
|
55
|
-
# Use the specified Rack middleware
|
56
65
|
def use(middleware, *args, &block)
|
57
|
-
@
|
58
|
-
@middleware << [middleware, args, block]
|
66
|
+
@middleware << lambda { |app| middleware.new(app, *args, &block) }
|
59
67
|
end
|
60
68
|
|
61
69
|
end
|
data/lib/angus/responses.rb
CHANGED
@@ -1,40 +1,10 @@
|
|
1
1
|
require 'angus/sdoc'
|
2
2
|
|
3
|
+
require_relative 'status_codes'
|
4
|
+
|
3
5
|
module Angus
|
4
6
|
module Responses
|
5
|
-
|
6
|
-
HTTP_STATUS_CODE_OK = 200
|
7
|
-
|
8
|
-
HTTP_STATUS_CODE_FORBIDDEN = 403
|
9
|
-
HTTP_STATUS_CODE_NOT_FOUND = 404
|
10
|
-
HTTP_STATUS_CODE_CONFLICT = 409
|
11
|
-
HTTP_STATUS_CODE_UNPROCESSABLE_ENTITY = 422
|
12
|
-
|
13
|
-
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500
|
14
|
-
|
15
|
-
# Returns a suitable HTTP status code for the given error
|
16
|
-
#
|
17
|
-
# If error param responds to #errors, then #{HTTP_STATUS_CODE_CONFLICT} will be returned.
|
18
|
-
#
|
19
|
-
# If error param responds to #error_key, then the status_code associated
|
20
|
-
# with the message will be returned.
|
21
|
-
#
|
22
|
-
# @param [#errors, #error_key] error An error object
|
23
|
-
#
|
24
|
-
# @return [Integer] HTTP status code
|
25
|
-
def get_error_status_code(error)
|
26
|
-
if error.respond_to?(:errors)
|
27
|
-
return HTTP_STATUS_CODE_CONFLICT
|
28
|
-
end
|
29
|
-
|
30
|
-
message = get_error_definition(error)
|
31
|
-
|
32
|
-
if message
|
33
|
-
message.status_code
|
34
|
-
else
|
35
|
-
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR
|
36
|
-
end
|
37
|
-
end
|
7
|
+
include Angus::StatusCodes
|
38
8
|
|
39
9
|
# Returns the error definition.
|
40
10
|
#
|
@@ -75,12 +45,6 @@ module Angus
|
|
75
45
|
json(elements)
|
76
46
|
end
|
77
47
|
|
78
|
-
# Builds a service error response
|
79
|
-
def build_error_response(error)
|
80
|
-
error_messages = messages_from_error(error)
|
81
|
-
build_response(:error, *error_messages)
|
82
|
-
end
|
83
|
-
|
84
48
|
# Builds a ResponseMessage object
|
85
49
|
#
|
86
50
|
# @param [#to_s] key Message key
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Angus
|
2
|
+
module StatusCodes
|
3
|
+
|
4
|
+
# TODO remove HTTP_STATUS from all constants
|
5
|
+
HTTP_STATUS_CODE_OK = 200
|
6
|
+
|
7
|
+
HTTP_STATUS_CODE_FORBIDDEN = 403
|
8
|
+
HTTP_STATUS_CODE_NOT_FOUND = 404
|
9
|
+
HTTP_STATUS_CODE_CONFLICT = 409
|
10
|
+
HTTP_STATUS_CODE_UNPROCESSABLE_ENTITY = 422
|
11
|
+
|
12
|
+
HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
self.constants.each do |const|
|
16
|
+
unless base.const_defined?(const)
|
17
|
+
base.const_set(const, self.const_get(const))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/angus/version.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
#require_relative '../definition_reader'
|
2
|
+
#require_relative '../responses'
|
3
|
+
#require_relative '../status_codes'
|
4
|
+
|
5
|
+
|
6
|
+
require 'spec_helper'
|
7
|
+
|
8
|
+
require 'angus/middleware/exception_handler'
|
9
|
+
|
10
|
+
work_dir = File.join(File.dirname(__FILE__), '..', '..', 'functional', 'basic')
|
11
|
+
describe Angus::Middleware::ExceptionHandler, { :work_dir => work_dir } do
|
12
|
+
|
13
|
+
let(:app) { double(:app, :call => app_response) }
|
14
|
+
|
15
|
+
let(:app_response) { :ok }
|
16
|
+
|
17
|
+
let(:env) { :env }
|
18
|
+
|
19
|
+
subject(:middleware) { Angus::Middleware::ExceptionHandler.new(app) }
|
20
|
+
|
21
|
+
it 'returns app response' do
|
22
|
+
middleware.call(env).should eq(app_response)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when unknown error' do
|
26
|
+
before { app.stub(:call).with(any_args).and_raise(Exception) }
|
27
|
+
|
28
|
+
it 'returns INTERNAL SERVER ERROR' do
|
29
|
+
response = middleware.call(env)
|
30
|
+
|
31
|
+
response.first.should eq(Angus::StatusCodes::HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when #errors' do
|
36
|
+
|
37
|
+
let(:error) { Exception.new }
|
38
|
+
|
39
|
+
before do
|
40
|
+
error.stub(:errors => [:errors])
|
41
|
+
app.stub(:call).with(any_args).and_raise(error)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns CONFLICT ERROR' do
|
45
|
+
response = middleware.call(env)
|
46
|
+
|
47
|
+
response.first.should eq(Angus::StatusCodes::HTTP_STATUS_CODE_CONFLICT)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when known error' do
|
52
|
+
let(:know_error) { UserNotFound = Class.new(StandardError) }
|
53
|
+
|
54
|
+
before { app.stub(:call).with(any_args).and_raise(know_error.new) }
|
55
|
+
|
56
|
+
it 'returns the status code set for the error' do
|
57
|
+
response = middleware.call(env)
|
58
|
+
|
59
|
+
response.first.should eq(Angus::StatusCodes::HTTP_STATUS_CODE_NOT_FOUND)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -16,7 +16,7 @@ get_user:
|
|
16
16
|
type: user_profile
|
17
17
|
|
18
18
|
messages:
|
19
|
-
- key:
|
19
|
+
- key: UserNotFound
|
20
20
|
|
21
21
|
get_users:
|
22
22
|
name: Obtener Lista de usuarios
|
@@ -30,8 +30,4 @@ get_users:
|
|
30
30
|
- element: users
|
31
31
|
description: Perfil del usuario
|
32
32
|
required: true
|
33
|
-
elements_type: user_profile
|
34
|
-
|
35
|
-
messages:
|
36
|
-
- key: ResourceNotFound
|
37
|
-
|
33
|
+
elements_type: user_profile
|
@@ -1,12 +1,18 @@
|
|
1
|
+
require_relative '../exceptions/user_errors'
|
2
|
+
|
1
3
|
class Users < Angus::BaseResource
|
2
|
-
USERS = [{ :id => 1, :name => 'ac/dc'},{:id => 2, :name => 'madonna' }]
|
4
|
+
USERS = [{ :id => 1, :name => 'ac/dc' }, { :id => 2, :name => 'madonna' }]
|
3
5
|
|
4
6
|
def get_user
|
5
|
-
|
7
|
+
user = USERS.find { |user| user[:id] == params[:user_id].to_i }
|
8
|
+
|
9
|
+
raise UserNotFound.new(params[:user_id]) unless user
|
10
|
+
|
11
|
+
{ :profile => user }
|
6
12
|
end
|
7
13
|
|
8
14
|
def get_users
|
9
|
-
{:users => USERS}
|
15
|
+
{ :users => USERS }
|
10
16
|
end
|
11
17
|
|
12
|
-
end
|
18
|
+
end
|
@@ -4,11 +4,10 @@ require 'rack/test'
|
|
4
4
|
|
5
5
|
require 'functional/basic/services/basic'
|
6
6
|
|
7
|
-
describe Spec::Functional::Basic do
|
7
|
+
describe Spec::Functional::Basic, { :work_dir => "#{File.dirname(__FILE__ )}/basic" } do
|
8
8
|
include Rack::Test::Methods
|
9
9
|
|
10
10
|
def app
|
11
|
-
Dir.chdir("#{File.dirname(__FILE__ )}/basic")
|
12
11
|
Spec::Functional::Basic.new
|
13
12
|
end
|
14
13
|
|
@@ -58,6 +57,30 @@ describe Spec::Functional::Basic do
|
|
58
57
|
last_response.header['Content-Type'].should eq('application/json')
|
59
58
|
end
|
60
59
|
|
60
|
+
context 'when a expected error happens' do
|
61
|
+
it 'sets the correct status code' do
|
62
|
+
get '/basic/api/0.1/users/-1'
|
63
|
+
|
64
|
+
last_response.status.should eq(404)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'sets a json content type' do
|
68
|
+
get '/basic/api/0.1/users/-1'
|
69
|
+
|
70
|
+
last_response.header['Content-Type'].should eq('application/json')
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'the response body' do
|
74
|
+
subject(:body) {
|
75
|
+
get '/basic/api/0.1/users/-1'
|
76
|
+
JSON(last_response.body)
|
77
|
+
}
|
78
|
+
|
79
|
+
its(['status']) { should eq('error')}
|
80
|
+
its(['messages']) { should include({ 'level' => 'error', 'key' => 'UserNotFound',
|
81
|
+
'dsc' => 'User with id=-1 not found' })}
|
82
|
+
end
|
83
|
+
end
|
61
84
|
end
|
62
85
|
|
63
86
|
end
|
@@ -4,11 +4,11 @@ require 'rack/test'
|
|
4
4
|
|
5
5
|
require 'functional/empty_resource/services/empty_resource'
|
6
6
|
|
7
|
-
describe Spec::Functional::EmptyResource
|
7
|
+
describe Spec::Functional::EmptyResource,
|
8
|
+
{ :work_dir => "#{File.dirname(__FILE__ )}/empty_resource" } do
|
8
9
|
include Rack::Test::Methods
|
9
10
|
|
10
11
|
def app
|
11
|
-
Dir.chdir("#{File.dirname(__FILE__ )}/empty_resource")
|
12
12
|
Spec::Functional::EmptyResource.new
|
13
13
|
end
|
14
14
|
|
@@ -4,11 +4,11 @@ require 'rack/test'
|
|
4
4
|
|
5
5
|
require 'functional/no_resources/services/no_resources'
|
6
6
|
|
7
|
-
describe Spec::Functional::NoResources
|
7
|
+
describe Spec::Functional::NoResources,
|
8
|
+
{ :work_dir => "#{File.dirname(__FILE__ )}/no_resources" } do
|
8
9
|
include Rack::Test::Methods
|
9
10
|
|
10
11
|
def app
|
11
|
-
Dir.chdir("#{File.dirname(__FILE__ )}/no_resources")
|
12
12
|
Spec::Functional::NoResources.new
|
13
13
|
end
|
14
14
|
|
data/spec/spec_helper.rb
CHANGED
@@ -24,4 +24,14 @@ RSpec.configure do |config|
|
|
24
24
|
# --seed 1234
|
25
25
|
config.order = 'random'
|
26
26
|
|
27
|
+
config.around(:each) do |example|
|
28
|
+
old_work_dir = Dir.pwd
|
29
|
+
|
30
|
+
Dir.chdir(example.metadata[:work_dir] || old_work_dir)
|
31
|
+
|
32
|
+
example.run
|
33
|
+
|
34
|
+
Dir.chdir(old_work_dir)
|
35
|
+
end
|
36
|
+
|
27
37
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-11-
|
14
|
+
date: 2013-11-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: thor
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '0.0'
|
40
40
|
- - ! '>='
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 0.0.
|
42
|
+
version: 0.0.4
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
version: '0.0'
|
51
51
|
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.0.
|
53
|
+
version: 0.0.4
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
55
|
name: angus-router
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,6 +214,7 @@ files:
|
|
214
214
|
- lib/angus/marshallings/marshalling.rb
|
215
215
|
- lib/angus/marshallings/base.rb
|
216
216
|
- lib/angus/generator.rb
|
217
|
+
- lib/angus/status_codes.rb
|
217
218
|
- lib/angus/version.rb
|
218
219
|
- lib/angus/base_actions.rb
|
219
220
|
- lib/angus/request_handler.rb
|
@@ -232,6 +233,7 @@ files:
|
|
232
233
|
- lib/angus/base_resource.rb
|
233
234
|
- lib/angus/command.rb
|
234
235
|
- lib/angus/response.rb
|
236
|
+
- lib/angus/middleware/exception_handler.rb
|
235
237
|
- lib/angus/rspec/support/examples/describe_errors.rb
|
236
238
|
- lib/angus/rspec/support/matchers/operation_response_matchers.rb
|
237
239
|
- lib/angus/rspec/support/operation_response.rb
|
@@ -241,12 +243,15 @@ files:
|
|
241
243
|
- lib/angus/utils/params.rb
|
242
244
|
- lib/angus/resource_definition.rb
|
243
245
|
- lib/angus/utils.rb
|
246
|
+
- lib/angus/definition_reader.rb
|
244
247
|
- lib/angus/base.rb
|
245
248
|
- lib/angus.rb
|
246
249
|
- spec/spec_helper.rb
|
250
|
+
- spec/angus/middleware/exception_handler_spec.rb
|
247
251
|
- spec/angus/rspec/examples/describe_errors_spec.rb
|
248
252
|
- spec/functional/no_resources_spec.rb
|
249
253
|
- spec/functional/empty_resource_spec.rb
|
254
|
+
- spec/functional/basic/exceptions/user_errors.rb
|
250
255
|
- spec/functional/basic/resources/users.rb
|
251
256
|
- spec/functional/basic/services/basic.rb
|
252
257
|
- spec/functional/basic/definitions/representations.yml
|
@@ -292,9 +297,11 @@ specification_version: 3
|
|
292
297
|
summary: angus
|
293
298
|
test_files:
|
294
299
|
- spec/spec_helper.rb
|
300
|
+
- spec/angus/middleware/exception_handler_spec.rb
|
295
301
|
- spec/angus/rspec/examples/describe_errors_spec.rb
|
296
302
|
- spec/functional/no_resources_spec.rb
|
297
303
|
- spec/functional/empty_resource_spec.rb
|
304
|
+
- spec/functional/basic/exceptions/user_errors.rb
|
298
305
|
- spec/functional/basic/resources/users.rb
|
299
306
|
- spec/functional/basic/services/basic.rb
|
300
307
|
- spec/functional/basic/definitions/representations.yml
|