kapellmeister 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42feaf3702c02c30f8e9d2c5d186a95486ca32397621d10fa4ceea3fbb91a342
4
- data.tar.gz: d331ac841f6e36f67b6e4d85fa0cb12932a8533b5ff228f5739c9807d672bc41
3
+ metadata.gz: 3f6050eee5b66fbd57d701c5c4af3cd6bc1ee34089d1a0aaa7cf90c7fed12fa3
4
+ data.tar.gz: 47d525ef9f511166657c397257b8989ca02dc6637c360c39a0354c355fa1a595
5
5
  SHA512:
6
- metadata.gz: 3018acc34db9d59433ccf03688124c46a3258f2046e59d411e874799d15fc17c41f3e90c61f06a2b834f5f29a1f7d47e198799207d4bd86b94821bad289398d4
7
- data.tar.gz: e4561bc80ead80c012ea0190915d04518734bade308997fc80125a92f63592b496388b13885cb7622c531f9fd79d81ee9121c18776e4a154206b62c2c63d3213
6
+ metadata.gz: 4471a0c7b78d03d30e3b61f977d81272aa434bb46c35d5f90bb310667cb2f913a2ba0797699401c8dfee6092fcec58c88643b396c0ba80ff46a9c31fa7b598fc
7
+ data.tar.gz: 200139ca7b308fe988c74a9047484b8ed95c78b62cedbba5ff1fd848e40b1d9e8c2fb3f6b6fe06bcfceadc0906bbbdfe7173ae3c652f20616811f804a9bc97aa
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ ruby '3.1.1'
4
4
 
5
5
  gemspec
6
6
 
7
+ gem 'dry-schema'
7
8
  gem 'faraday'
8
9
  gem 'faraday_middleware'
9
10
  gem 'faraday-cookie_jar'
data/README.md CHANGED
@@ -7,7 +7,7 @@ This template-service allows you to define http requests to a third party throug
7
7
  Add kapellmeister to your Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'kapellmeister', '~> 0.0.1', require: false
10
+ gem 'kapellmeister', '~> 0.4.1'
11
11
  ```
12
12
 
13
13
  ### Add new third party configuration:
@@ -27,6 +27,7 @@ Gem::Specification.new do |gem|
27
27
 
28
28
  gem.required_ruby_version = '>= 2.4.2'
29
29
 
30
+ gem.add_dependency 'dry-schema', '~> 1.9.1'
30
31
  gem.add_dependency 'faraday', '~> 1.0'
31
32
  gem.add_dependency 'faraday-cookie_jar', '~> 0.0.7'
32
33
  gem.add_dependency 'faraday_middleware', '~> 1.2'
@@ -50,3 +50,8 @@ module Kapellmeister
50
50
  end
51
51
  end
52
52
  end
53
+
54
+ # ROUTES = Dir['app/lib/yandex_taxi/route_scheme/**/*.yml'].each_with_object({}) do |file, result|
55
+ # routes = ::Kapellmeister::Base.routes_scheme_parse(file)
56
+ # result.merge!(routes)
57
+ # end
@@ -1,5 +1,5 @@
1
1
  class <%= class_name %>::Configuration
2
- attr_accessor <%= [*initialize_signatures, :path, :logger].map { |k| ":#{k}" }.join(', ') %>
2
+ attr_accessor <%= [*initialize_signatures, :ssl, :path, :logger].map { |k| ":#{k}" }.join(', ') %>
3
3
 
4
4
  def initialize
5
5
  @path = ''
@@ -11,6 +11,6 @@ class <%= class_name %>::Configuration
11
11
 
12
12
  https = ssl.presence || true
13
13
 
14
- "URI::HTTP#{https.to_b ? 'S' : ''}".build(host:, path: [path, version].join('/'))
14
+ "URI::HTTP#{https.to_b ? 'S' : ''}".constantize.build(host:, path: [path, version].join('/'))
15
15
  end
16
16
  end
@@ -0,0 +1,30 @@
1
+ class <%= class_name %>::Responder
2
+ Result = Struct.new(:success?, :response, :payload)
3
+ attr_reader :response, :payload
4
+
5
+ delegate :body, :status, to: :response
6
+
7
+ def initialize(response, **args)
8
+ @response = response
9
+ @payload = args
10
+ end
11
+
12
+ def result
13
+ error = !/2\d{2}/.match?(status.to_s)
14
+
15
+ Result.new(!error, parsed_body, { status: }.merge(payload))
16
+ rescue JSON::ParserError => e
17
+ Result.new(false, e)
18
+ end
19
+
20
+ private
21
+
22
+ def parsed_body
23
+ return body if body.length.zero?
24
+
25
+ case body
26
+ when Hash then body
27
+ else JSON.parse(body, symbolize_names: true, quirks_mode: true)
28
+ end
29
+ end
30
+ end
@@ -2,10 +2,11 @@
2
2
  # foo: => Wrapper for method
3
3
  # bar: => Method name
4
4
  # scheme: => Scheme description
5
- # method: POST => Request type
6
- # use_wrapper: true => Default true
7
- # path: buz => Real path
8
- # mock: => Mock for development
9
- # token: blablabla
5
+ # method: POST => Request type (* required)
6
+ # use_wrapper: true => Default true (* required)
7
+ # path: buz => Real path (* required)
8
+ # body: => Dry schema for checking parameters. If key doesn't exist nothing happens
9
+ # query: => Query params. If key doesn't exist nothing happens
10
+ # mock: => Structure or Path to mock file for tests. If key doesn't exist nothing happens
10
11
  #
11
12
  # Client.foo_bar { a: 'b' } => POST http://host/foo/buz DATA: { a: 'b' }
@@ -4,11 +4,10 @@ module <%= class_name %>
4
4
  class << self
5
5
  include ::Kapellmeister::Base
6
6
 
7
- <%- initialize_signatures.each do |attr| -%>
8
- <%= "def #{attr}" %>
9
- <%= "@#{attr} ||= configuration.#{attr}" %>
10
- <%= "end" %>
7
+ delegate <%= initialize_signatures.map { |k| ":#{k}" }.join(', ') %>, to: :configuration
11
8
 
12
- <%- end -%>
9
+ def ssl
10
+ @ssl ||= true
11
+ end
13
12
  end
14
13
  end
@@ -26,14 +26,18 @@ module Kapellmeister::Base
26
26
  end
27
27
 
28
28
  def self.routes_scheme_parse(path)
29
- YAML.safe_load(ERB.new(File.read(path)).result, aliases: true, permitted_classes: [Time]).deep_symbolize_keys
29
+ template = ERB.new(File.read(path)).result
30
+ YAML.safe_load(template, aliases: true, permitted_classes: [Symbol, Date, Time]).deep_symbolize_keys
31
+ rescue Errno::ENOENT => e
32
+ warn "No such file or directory", path
33
+ {}
30
34
  end
31
35
  end
32
36
 
33
37
  def generate_routes(json_scheme)
34
- json_scheme.each_with_object({}) do |(key, value), scheme|
38
+ json_scheme.dup.each_with_object({}) do |(key, value), scheme|
35
39
  scheme[key] = value.delete(:scheme) if (value.is_a?(Hash) && value.key?(:scheme)) || value.is_a?(String)
36
- next if value.length.zero?
40
+ next if value.nil? || value.length.zero?
37
41
 
38
42
  generate_routes(value).map { |deep_key, deep_value| mapping(deep_key, deep_value, key, scheme) }
39
43
  end
@@ -6,37 +6,30 @@ class Kapellmeister::Dispatcher
6
6
  base.extend(Kapellmeister::RequestsExtension)
7
7
 
8
8
  delegate :report, :configuration, :logger, to: base.module_parent
9
-
10
- lambda {
11
- @custom_headers ||= try(:headers) || {}
12
- @custom_request_options ||= try(:request_options) || {}
13
- }.call
14
9
  end
15
10
 
16
11
  FailedResponse = Struct.new(:success?, :response, :payload)
17
12
 
18
- def connection_by(method, path, data = {})
19
- headers_params = data.delete(:headers) || {}
13
+ def connection_by(method_name, path, data = {}, query = {})
14
+ additional_headers = data.delete(:headers) || {}
20
15
  requests_data = data.delete(:request) || {}
21
16
 
22
- generated_connection = connection(additional_headers: headers_params, requests_data:)
17
+ generated_connection = connection(additional_headers:, requests_data:)
23
18
 
24
- case method.upcase.to_sym
25
- when :GET
26
- process generated_connection.get([path, data.to_query].compact_blank!.join('?'))
27
- when :POST
28
- process generated_connection.post(path, data.to_json)
29
- when :PUT
30
- process generated_connection.put(path, data.to_json)
31
- else
32
- raise "Library can't process method #{method} yet"
33
- end
19
+ process generated_connection.run_request(method_name.downcase.to_sym, path, data.to_json, additional_headers)
20
+ rescue NoMethodError, NameError, RuntimeError
21
+ raise "Library can't process method #{method_name} yet"
34
22
  rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
35
23
  failed_response(details: e.message)
36
24
  end
37
25
 
38
- def self.headers; end
39
- def self.request_options; end
26
+ def headers
27
+ {}
28
+ end
29
+
30
+ def request_options
31
+ {}
32
+ end
40
33
 
41
34
  private
42
35
 
@@ -44,8 +37,7 @@ class Kapellmeister::Dispatcher
44
37
  ::Faraday.new(url: configuration.url,
45
38
  headers: headers_generate(**additional_headers),
46
39
  request: requests_generate(**requests_data)) do |faraday|
47
- faraday.request :authorization, *authorization
48
- faraday.request :json, content_type: 'application/json'
40
+ faraday.request :json, content_type: 'application/json; charset=utf-8'
49
41
  faraday.request :multipart
50
42
  faraday.response :logger, logger
51
43
  faraday.response :json, content_type: 'application/json; charset=utf-8'
@@ -57,16 +49,16 @@ class Kapellmeister::Dispatcher
57
49
 
58
50
  def headers_generate(**additional)
59
51
  {
60
- accept: 'application/json, text/plain, */*',
52
+ accept: 'application/json, text/plain, */*, charset=utf-8',
61
53
  **additional,
62
- **@custom_headers
54
+ **headers
63
55
  }
64
56
  end
65
57
 
66
58
  def requests_generate(**requests_data)
67
59
  {
68
60
  **requests_data,
69
- **@custom_request_options
61
+ **request_options
70
62
  }
71
63
  end
72
64
 
@@ -2,16 +2,15 @@ module Kapellmeister::RequestsExtension
2
2
  def self.request_processing
3
3
  proc do |name, request_data|
4
4
  define_method name do |data = {}|
5
- proc { |method:, path:, mock:| # rubocop:disable Lint/UnusedBlockArgument:
6
- # return mock if ENV['APP_ENV'] == 'development'
5
+ proc { |method:, path:, body: {}, query: {}, mock: ''|
6
+ return ::Kapellmeister::Base.routes_scheme_parse(mock) if (Rails.try(:env) || ENV['APP_ENV']) == 'test'
7
7
 
8
- path = path.split('/').map do |part|
9
- next part unless part.include? '%<'
8
+ valid_body?(data, body)
9
+ valid_query?(data, query)
10
10
 
11
- data.delete(part.match(/%<(.*)>/).to_a.last.to_sym)
12
- end.join('/')
11
+ full_path = generate_full_path(path, data)
13
12
 
14
- new.connection_by(method, path, data)
13
+ new.connection_by(method, full_path, data)
15
14
  }.call(**request_data)
16
15
  end
17
16
  end
@@ -23,3 +22,41 @@ module Kapellmeister::RequestsExtension
23
22
  base.module_parent.requests.each(&request_processing)
24
23
  end
25
24
  end
25
+
26
+ def generate_full_path(original_path, data)
27
+ path = generate_path(original_path, data)
28
+ [path, data.delete(:query)&.to_query].compact_blank!.join('?')
29
+ end
30
+
31
+ def generate_path(original_path, data)
32
+ original_path.split('/').map do |part|
33
+ next part unless part.include? '%<'
34
+
35
+ data.delete(part.match(/%<(.*)>/).to_a.last.to_sym)
36
+ end.join('/')
37
+ end
38
+
39
+ def valid_body?(data, body)
40
+ return if body.blank? || body.is_a?(Hash)
41
+
42
+ schema = Object.const_get(body).schema
43
+ result = schema.(data)
44
+ return data if result.success?
45
+
46
+ raise ArgumentError, result.errors.to_h
47
+ end
48
+
49
+ def valid_query?(data, query)
50
+ return if query.blank?
51
+ required_keys = query.keys
52
+
53
+ from_data = data.slice(*required_keys)
54
+ data.except!(*required_keys)
55
+ data[:query] ||= {}
56
+ data[:query] = data[:query].to_h.merge!(from_data)
57
+
58
+ diffirent_keys = data[:query].transform_keys(&:to_sym)
59
+ return if required_keys.all? { |key| diffirent_keys.has_key? key.to_sym }
60
+
61
+ raise ArgumentError, "query params needs keys #{required_keys}"
62
+ end
@@ -12,7 +12,7 @@ class Kapellmeister::Responder
12
12
  def result
13
13
  error = !/2\d{2}/.match?(status.to_s)
14
14
 
15
- Result.new(!error, parsed_body, { status: status }.merge(payload))
15
+ Result.new(!error, parsed_body, { status: }.merge(payload))
16
16
  rescue JSON::ParserError => e
17
17
  Result.new(false, e)
18
18
  end
@@ -20,7 +20,7 @@ class Kapellmeister::Responder
20
20
  private
21
21
 
22
22
  def parsed_body
23
- return body if body.length == 0
23
+ return body if body.empty?
24
24
 
25
25
  case body
26
26
  when Hash then body
@@ -1,3 +1,3 @@
1
1
  module Kapellmeister
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kapellmeister
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarkWater
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-29 00:00:00.000000000 Z
11
+ date: 2022-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-schema
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.9.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.9.1
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement