ant-server 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: acabc2e20fc8bae1543886e5199127f83097f601627c57c32ed47bd1c2c5110c
4
+ data.tar.gz: d21714db5880cffba818daeab9b081d538fb7ea17e6d01271bd79333dd965bae
5
+ SHA512:
6
+ metadata.gz: e6944cd4e4f34945a9e22032b35956fc10618a3833bd59d6cd1ebf0d02f8aa5a7d71541a4cde84a716f3a9f0bbde6b3dfbae2a8171459b75892a71ed18fe300b
7
+ data.tar.gz: 4cc1e301c82ee8316f36d211a36353d3444b986307ffa4674c27bb9fcbc4fc5cb2a32a43435ada917168c10e59a0ea9b5002912155a91593fb65e11b524040aa
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ant/core'
4
+
5
+ require_relative 'version'
6
+ require_relative 'server/response'
7
+ require_relative 'server/format'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ant
4
+ module Server
5
+ ##
6
+ # See Exceptions module, since this is based on the exceptions too.
7
+ # This will wrap a json object into a standard format, where the response
8
+ # will contain some metadata about the status of the request
9
+ class Format
10
+ INTERNAL_SERVER_ERROR_CODE = 'INTERNAL_SERVER_ERROR'
11
+ INTERNAL_SERVER_ERROR_MESSAGE = 'Unexpected error ocurred!'
12
+ ##
13
+ # success means there were no errors during the execution of the request
14
+ # it sends the result in the data field.
15
+ def success(response)
16
+ { status: :success, data: response.result || response.data }
17
+ end
18
+
19
+ ##
20
+ # an error on the request. It gives the details of the error.
21
+ def fail(response)
22
+ error_format(:fail, response.code, response.message, response.data)
23
+ end
24
+
25
+ ##
26
+ # an error found while resolving the request.
27
+ def error(response)
28
+ error_format(:error, response.code, response.message, response.data)
29
+ end
30
+
31
+ ##
32
+ # an unhandled error ocurred during the execution of the request.
33
+ def fatal(_data)
34
+ error_format(:fatal, INTERNAL_SERVER_ERROR_CODE,
35
+ INTERNAL_SERVER_ERROR_MESSAGE, {})
36
+ end
37
+
38
+ ##
39
+ # helper to sumarize fatal and error status
40
+ def error_format(level, code, message, data)
41
+ { status: level, code: code, message: message, data: data }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ant
4
+ module Server
5
+ # Descorator for using grape with ant.
6
+ # This will implement:
7
+ # - exception handling
8
+ # - logs
9
+ # - JSend format
10
+ module GrapeDecorator
11
+ def self.handler
12
+ lambda do |env, level, ex|
13
+ params = env['api.endpoint'].params
14
+ request = env['api.endpoint'].request
15
+ pkg = RequestResponse.new(request: request, params: params)
16
+ pkg.exception = ex
17
+ Server::Response.logger.send(level, pkg)
18
+ Server::Response.format.send(level, pkg)
19
+ end
20
+ end
21
+
22
+ HTTP_CODES = {
23
+ success: 200, fail: 400, error: 500, fatal: 500
24
+ }.freeze
25
+
26
+ def self.extract_http_code(exception, level)
27
+ default = HTTP_CODES[level] || 500
28
+ exception.respond_to?(:http_code) ? exception.http_code : default
29
+ end
30
+
31
+ def self.configure_custom_exceptions(base)
32
+ Server::Response.resources(:exceptions).each do |exception_class, level|
33
+ base.rescue_from(exception_class) do |ex|
34
+ response = Ant::Server::GrapeDecorator.handler.call(env, level, ex)
35
+ http_code = Ant::Server::GrapeDecorator.extract_http_code(ex, level)
36
+ error!(response, http_code)
37
+ end
38
+ end
39
+ end
40
+
41
+ # :nocov: #
42
+ def self.configure_grape_exceptions(base)
43
+ base.rescue_from(Grape::Exceptions::Base) do |ex|
44
+ ant_ex = Ant::Exceptions::AntFail.new(ex.message)
45
+ response = Ant::Server::GrapeDecorator
46
+ .handler.call(env, :fail, ant_ex)
47
+ error!(response, 400)
48
+ end
49
+ end
50
+ # :nocov: #
51
+
52
+ def self.configure_global_exception_handler(base)
53
+ base.rescue_from(:all) do |ex|
54
+ level = :fatal
55
+ response = Ant::Server::GrapeDecorator.handler.call(env, level, ex)
56
+ http_code = Ant::Server::GrapeDecorator.extract_http_code(ex, level)
57
+ error!(response, http_code)
58
+ end
59
+ end
60
+
61
+ def self.configure_handlers(base)
62
+ configure_custom_exceptions(base)
63
+ configure_grape_exceptions(base)
64
+ configure_global_exception_handler(base)
65
+ end
66
+
67
+ def self.included(base)
68
+ base.formatter(:json, lambda do |response, _|
69
+ pkg = RequestResponse.new(request: {}, params: {})
70
+ pkg.result = response
71
+ Server::Response.format.send(:success, pkg).to_json
72
+ end)
73
+ configure_logger(base)
74
+ configure_handlers(base)
75
+ end
76
+
77
+ def self.configure_logger(base)
78
+ base.before do
79
+ params[:__init_time] = Time.now
80
+ end
81
+ base.after do
82
+ params = env['api.endpoint'].params
83
+ request = env['api.endpoint'].request
84
+ pkg = RequestResponse.new(request: request, params: params)
85
+ Server::Response.logger.access(pkg)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ant/logger'
4
+ module Ant
5
+ module Server
6
+ # Implements monitoring. This will add logs.
7
+ # Currently it only support CuteLogger format, but it will be deprecated
8
+ # in order to support a new log (actually kind of the same format).
9
+ class Logger
10
+ include Ant::Logger
11
+ def access_data(response)
12
+ {
13
+ path: response.path,
14
+ ip: response.ip,
15
+ verb: response.verb,
16
+ processing_time:
17
+ (Time.now - response.params[:__init_time]).to_f * 1000
18
+ }
19
+ end
20
+
21
+ def access(response)
22
+ log_info('Requesting resource', access_data(response))
23
+ end
24
+
25
+ def success(response)
26
+ log_info('Success request', access_data(response))
27
+ end
28
+
29
+ def fail(response)
30
+ log_info('Fail Response',
31
+ access_data(response)
32
+ .merge(message: response.exception.message))
33
+ end
34
+
35
+ def error(response)
36
+ log_warn('Error dectected on response', access_data(response).merge(
37
+ error: response.exception
38
+ ))
39
+ end
40
+
41
+ def fatal(response)
42
+ log_error('Unexpected error on response',
43
+ access_data(response).merge(
44
+ error: response.exception,
45
+ data: response.params
46
+ ))
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ant
4
+ module Server
5
+ # Wraps the request and the response into an object so it is easier
6
+ # to track monitoring logs and format the response after the endpoint was
7
+ # executed
8
+ class RequestResponse
9
+ attr_reader :params, :exception, :result, :start_timestamp
10
+ attr_writer :exception, :result, :start_timestamp
11
+ def initialize(request:, params:)
12
+ @request = request
13
+ @params = params
14
+ @start_timestamp = Time.now
15
+ end
16
+
17
+ def data
18
+ @exception.data
19
+ end
20
+
21
+ def code
22
+ @exception.code
23
+ end
24
+
25
+ def verb
26
+ @request.request_method
27
+ end
28
+
29
+ def ip
30
+ @request.ip
31
+ end
32
+
33
+ def message
34
+ @exception.message
35
+ end
36
+
37
+ def path
38
+ @request.env['PATH_INFO']
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'format'
4
+ require_relative 'logger'
5
+ require_relative 'request_response'
6
+
7
+ module Ant
8
+ module Server
9
+ ##
10
+ # This module provides a function to wrap lambdas arround grape/sinatra
11
+ # You can mount this module as helper in your application and wrap the block
12
+ # with the method `process_request`
13
+ module Response
14
+ include Exceptions
15
+ extend DRY::ResourceInjector
16
+
17
+ class << self
18
+ attr_reader :logger, :format
19
+
20
+ def log_mode(mode)
21
+ @logger = resource(:loggers, mode)
22
+ end
23
+
24
+ def format_mode(mode)
25
+ @format = resource(:formats, mode)
26
+ end
27
+
28
+ def recover_from!(exception_class, level)
29
+ register(:exceptions, exception_class, level)
30
+ end
31
+
32
+ def configure_defaults!
33
+ recover_from!(Exceptions::AntSuccess, :success)
34
+ recover_from!(Exceptions::AntFail, :fail)
35
+ recover_from!(Exceptions::AntError, :error)
36
+ register(:loggers, :cute_logger, Server::Logger.new)
37
+ register(:formats, :jsend, Server::Format.new)
38
+ log_mode(:cute_logger)
39
+ format_mode(:jsend)
40
+ end
41
+ end
42
+
43
+ def exception_handler(exception)
44
+ Server::Response.resources(:exceptions).each do |klass, recover|
45
+ return recover if exception.is_a?(klass)
46
+ end
47
+ exception.is_a?(StandardError) ? :fatal : nil
48
+ end
49
+
50
+ def handle(resolver, data)
51
+ if resolver
52
+ Server::Response.logger.send(resolver, data)
53
+ Server::Response.format.send(resolver, data)
54
+ else
55
+ Server::Response.logger.fatal(data)
56
+ raise(data.exception)
57
+ end
58
+ end
59
+
60
+ def process_request
61
+ params[:__init_time] = Time.now
62
+ data = RequestResponse.new(request: request, params: params)
63
+ resolver = :success
64
+ Server::Response.logger.access(data)
65
+ begin
66
+ raise(AntError, 'No implementation given') unless block_given?
67
+
68
+ data.result = yield
69
+ # rubocop: disable RescueException
70
+ rescue Exception => ex
71
+ # rubocop: enable RescueException
72
+ data.exception = ex
73
+ resolver = exception_handler(ex)
74
+ end
75
+ handle(resolver, data)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ # Allow backwards compatibility
82
+ Ant::Server::Response.configure_defaults!
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ant
4
+ module Server
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ant-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gilberto Vargas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ant-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ant-logger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: grape
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rdoc
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '6.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '6.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.16'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.16'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.5'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '3.5'
167
+ description: This gems can be used along a server app with jsonformat messages
168
+ email:
169
+ - tachoguitar@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - lib/ant/server.rb
175
+ - lib/ant/server/format.rb
176
+ - lib/ant/server/grape.rb
177
+ - lib/ant/server/logger.rb
178
+ - lib/ant/server/request_response.rb
179
+ - lib/ant/server/response.rb
180
+ - lib/ant/version.rb
181
+ homepage: https://github.com/tachomex/ant
182
+ licenses:
183
+ - MIT
184
+ metadata: {}
185
+ post_install_message:
186
+ rdoc_options: []
187
+ require_paths:
188
+ - lib
189
+ required_ruby_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ required_rubygems_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ requirements: []
200
+ rubygems_version: 3.0.3
201
+ signing_key:
202
+ specification_version: 4
203
+ summary: Implements ANT format on server applications
204
+ test_files: []