ant-server 0.1.0
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 +7 -0
- data/lib/ant/server.rb +7 -0
- data/lib/ant/server/format.rb +45 -0
- data/lib/ant/server/grape.rb +90 -0
- data/lib/ant/server/logger.rb +50 -0
- data/lib/ant/server/request_response.rb +42 -0
- data/lib/ant/server/response.rb +82 -0
- data/lib/ant/version.rb +7 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -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
|
data/lib/ant/server.rb
ADDED
@@ -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!
|
data/lib/ant/version.rb
ADDED
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: []
|