http_store 0.1.0 → 0.2.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: 37267dbaf2e539e27cb577b0774c53c1cc78b0ab601dfeb939bce2c8a24b3183
4
- data.tar.gz: 9bd3f0cb27141be490293d52a1dfed63d14e09d0d2fd8348b295047e1ebfe6b1
3
+ metadata.gz: e46d9d716290cd38b9293d0d3ae10a6d387cb2ce02712e180fdd060a9da2bb2b
4
+ data.tar.gz: a313bfb9874387e2f3a3a738d05c273b883824cccdd826b9eb85fba2008dfc54
5
5
  SHA512:
6
- metadata.gz: 22773739e8b21d29dccc55f3348b5e1199dfea8084a599a260d10ba33c2ba9db06016f9303e3f290cac680a5e31ddd2eafc52e34475f8ebdadf008df58fbe841
7
- data.tar.gz: 4aa1805a664e2e4a3fea921b924eba2ba52bb9464f1cfe386d625ded5bf62961339f291a57c202baf8369be01e2ff0b846c151d111388cb0df98db42f7d8d3d5
6
+ metadata.gz: 752515be72b99a4ea27e493c143afdedb69308bb37d92ffca0ea1de584a075150e63f5dc1a3d0c4da018a76947b32fd35d1ece54cd825988468f05b799691758
7
+ data.tar.gz: 1c25fd60ad38d88054189b5faa7e7d2b3ffba5c9cb681e4800919fa9c3ddd57ac7f39332993f20f4489f29fc5266b459e3ec75dad75c2de6f4ec7e807cece368
data/.gitignore CHANGED
@@ -9,3 +9,11 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ .byebug_history
13
+
14
+ # Ignore RubyMine files
15
+ .idea
16
+
17
+ # Ignore bundler config.
18
+ .bundle
19
+ /vendor/bundle
data/Gemfile.lock CHANGED
@@ -1,42 +1,119 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- http_store (0.1.0)
4
+ http_store (0.2.0)
5
5
  activerecord (>= 5.0, < 6.1)
6
6
  hashie (~> 3.0)
7
+ rails (>= 5, < 7)
7
8
  rest-client (~> 2.0)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
13
+ actioncable (5.2.3)
14
+ actionpack (= 5.2.3)
15
+ nio4r (~> 2.0)
16
+ websocket-driver (>= 0.6.1)
17
+ actionmailer (5.2.3)
18
+ actionpack (= 5.2.3)
19
+ actionview (= 5.2.3)
20
+ activejob (= 5.2.3)
21
+ mail (~> 2.5, >= 2.5.4)
22
+ rails-dom-testing (~> 2.0)
23
+ actionpack (5.2.3)
24
+ actionview (= 5.2.3)
25
+ activesupport (= 5.2.3)
26
+ rack (~> 2.0)
27
+ rack-test (>= 0.6.3)
28
+ rails-dom-testing (~> 2.0)
29
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
30
+ actionview (5.2.3)
31
+ activesupport (= 5.2.3)
32
+ builder (~> 3.1)
33
+ erubi (~> 1.4)
34
+ rails-dom-testing (~> 2.0)
35
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
36
+ activejob (5.2.3)
37
+ activesupport (= 5.2.3)
38
+ globalid (>= 0.3.6)
12
39
  activemodel (5.2.3)
13
40
  activesupport (= 5.2.3)
14
41
  activerecord (5.2.3)
15
42
  activemodel (= 5.2.3)
16
43
  activesupport (= 5.2.3)
17
44
  arel (>= 9.0)
45
+ activestorage (5.2.3)
46
+ actionpack (= 5.2.3)
47
+ activerecord (= 5.2.3)
48
+ marcel (~> 0.3.1)
18
49
  activesupport (5.2.3)
19
50
  concurrent-ruby (~> 1.0, >= 1.0.2)
20
51
  i18n (>= 0.7, < 2)
21
52
  minitest (~> 5.1)
22
53
  tzinfo (~> 1.1)
23
54
  arel (9.0.0)
55
+ builder (3.2.3)
24
56
  byebug (11.0.1)
25
57
  concurrent-ruby (1.1.5)
58
+ crass (1.0.4)
26
59
  diff-lcs (1.3)
27
60
  domain_name (0.5.20190701)
28
61
  unf (>= 0.0.5, < 1.0.0)
62
+ erubi (1.8.0)
63
+ globalid (0.4.2)
64
+ activesupport (>= 4.2.0)
29
65
  hashie (3.6.0)
30
66
  http-accept (1.7.0)
31
67
  http-cookie (1.0.3)
32
68
  domain_name (~> 0.5)
33
69
  i18n (1.6.0)
34
70
  concurrent-ruby (~> 1.0)
71
+ loofah (2.2.3)
72
+ crass (~> 1.0.2)
73
+ nokogiri (>= 1.5.9)
74
+ mail (2.7.1)
75
+ mini_mime (>= 0.1.1)
76
+ marcel (0.3.3)
77
+ mimemagic (~> 0.3.2)
78
+ method_source (0.9.2)
35
79
  mime-types (3.3)
36
80
  mime-types-data (~> 3.2015)
37
81
  mime-types-data (3.2019.0904)
82
+ mimemagic (0.3.3)
83
+ mini_mime (1.0.2)
84
+ mini_portile2 (2.4.0)
38
85
  minitest (5.11.3)
39
86
  netrc (0.11.0)
87
+ nio4r (2.5.1)
88
+ nokogiri (1.10.4)
89
+ mini_portile2 (~> 2.4.0)
90
+ rack (2.0.7)
91
+ rack-test (1.1.0)
92
+ rack (>= 1.0, < 3)
93
+ rails (5.2.3)
94
+ actioncable (= 5.2.3)
95
+ actionmailer (= 5.2.3)
96
+ actionpack (= 5.2.3)
97
+ actionview (= 5.2.3)
98
+ activejob (= 5.2.3)
99
+ activemodel (= 5.2.3)
100
+ activerecord (= 5.2.3)
101
+ activestorage (= 5.2.3)
102
+ activesupport (= 5.2.3)
103
+ bundler (>= 1.3.0)
104
+ railties (= 5.2.3)
105
+ sprockets-rails (>= 2.0.0)
106
+ rails-dom-testing (2.0.3)
107
+ activesupport (>= 4.2.0)
108
+ nokogiri (>= 1.6)
109
+ rails-html-sanitizer (1.2.0)
110
+ loofah (~> 2.2, >= 2.2.2)
111
+ railties (5.2.3)
112
+ actionpack (= 5.2.3)
113
+ activesupport (= 5.2.3)
114
+ method_source
115
+ rake (>= 0.8.7)
116
+ thor (>= 0.19.0, < 2.0)
40
117
  rake (10.5.0)
41
118
  rest-client (2.1.0)
42
119
  http-accept (>= 1.7.0, < 2.0)
@@ -56,12 +133,23 @@ GEM
56
133
  diff-lcs (>= 1.2.0, < 2.0)
57
134
  rspec-support (~> 3.8.0)
58
135
  rspec-support (3.8.2)
136
+ sprockets (3.7.2)
137
+ concurrent-ruby (~> 1.0)
138
+ rack (> 1, < 3)
139
+ sprockets-rails (3.2.1)
140
+ actionpack (>= 4.0)
141
+ activesupport (>= 4.0)
142
+ sprockets (>= 3.0.0)
143
+ thor (0.20.3)
59
144
  thread_safe (0.3.6)
60
145
  tzinfo (1.2.5)
61
146
  thread_safe (~> 0.1)
62
147
  unf (0.1.4)
63
148
  unf_ext
64
149
  unf_ext (0.0.7.6)
150
+ websocket-driver (0.7.1)
151
+ websocket-extensions (>= 0.1.0)
152
+ websocket-extensions (0.1.4)
65
153
 
66
154
  PLATFORMS
67
155
  ruby
@@ -1,24 +1,32 @@
1
- class CreateRestRequests < ActiveRecord::Migration[5.2]
1
+ class CreateHttpLogs < ActiveRecord::Migration[5.2]
2
2
  def change
3
- create_table :rest_requests do |t|
3
+ create_table :http_logs do |t|
4
+ # request
4
5
  t.string :http_method, comment: '请求方法'
5
6
  t.string :url, comment: '请求 URL'
7
+ t.string :data_type, comment: 'data 参数类型 (form/json)'
6
8
  t.text :headers, comment: '请求 header'
7
9
  t.text :query_params, comment: 'url 参数'
8
- t.string :data_type, comment: 'data 参数类型 (form/json)'
9
- t.text :data, comment: '参数'
10
- t.text :request_data, comment: '可能和 query params 重复'
10
+ t.text :data, comment: 'body, get/delete 为空'
11
11
 
12
+ # request builder
13
+ t.text :other_params, comment: '其他自定义参数, 用于构建 query_params/data_type'
14
+ t.string :request_digest, comment: '请求唯一 id'
15
+ t.boolean :request_valid, comment: '请求是否符合规范, 若为 false, 不会发起请求'
16
+
17
+ # response
12
18
  t.integer :status_code, comment: 'response http code'
13
19
  t.text :response, comment: 'response body'
14
20
  t.text :response_headers, comment: 'response header'
15
- t.boolean :response_status, comment: '请求结果 true/false, 这个要根据业务逻辑来设定. 不能靠 status_code 来确定'
21
+
22
+ # response checker
23
+ t.boolean :response_valid, comment: '请求结果 true/false, 这个要根据业务逻辑来设定. 不能靠 status_code 来确定'
16
24
  t.text :response_data, comment: '格式化后的 response'
17
25
 
26
+ # relation
18
27
  t.string :type, comment: '请求类型'
19
28
  t.string :requestable_id, comment: '外键 ID'
20
29
  t.string :requestable_type, comment: '外键 类型'
21
- t.boolean :is_valid, comment: '请求是否成功'
22
30
 
23
31
  t.timestamps
24
32
  end
data/http_store.gemspec CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "rest-client", '~> 2.0'
31
31
  spec.add_dependency "hashie", '~> 3.0'
32
32
  spec.add_dependency "activerecord", '>= 5.0', '< 6.1'
33
+ spec.add_dependency "rails", ">= 5", "< 7"
33
34
 
34
35
  spec.add_development_dependency "bundler", "~> 2.0"
35
36
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,79 @@
1
+ module HttpStore
2
+ class Client
3
+ META_KEYS = %w[http_method url data_type headers query_params data other_params request_valid
4
+ status_code response response_headers response_valid response_data
5
+ request_digest type requestable requestable_id requestable_type response_obj]
6
+
7
+ attr_accessor :meta
8
+
9
+ include HttpStore::Requestable
10
+ include HttpStore::Responseable
11
+
12
+ def self.execute(requestable, other_params = {})
13
+ new(requestable: requestable,
14
+ type: to_s,
15
+ other_params: other_params)
16
+ end
17
+
18
+ def initialize(args)
19
+ @meta = Hashie::Mash.new(args)
20
+ @meta.request_digest = gen_request_digest(@meta.to_json)
21
+
22
+ build_request
23
+
24
+ execute if request_valid # send request
25
+ raise HttpStore::RequestError, 'response_obj is nil' if response_obj.nil?
26
+
27
+ build_response
28
+ ensure
29
+ store_request
30
+ end
31
+
32
+ def gen_request_digest(str)
33
+ Digest::SHA1.hexdigest(str)
34
+ end
35
+
36
+ META_KEYS.each do |meta_key|
37
+ define_method meta_key do
38
+ @meta.send(meta_key)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def build_request
45
+ add_meta(set_request)
46
+ format_request
47
+ end
48
+
49
+ def add_meta(hash)
50
+ @meta.merge! Hashie::Mash.new(hash).slice(*META_KEYS)
51
+ end
52
+
53
+ def execute
54
+ @meta.response_obj = get? ? http_get_execute : http_post_execute
55
+ end
56
+
57
+ def http_get_execute
58
+ RestClient.get(uri, headers)
59
+ rescue RestClient::ExceptionWithResponse => e
60
+ # :nocov:
61
+ e.response
62
+ # :nocov:
63
+ end
64
+
65
+ def http_post_execute
66
+ real_data = json_request? ? data.to_json : data.to_hash
67
+ RestClient.post(uri, real_data, headers.symbolize_keys)
68
+ rescue RestClient::ExceptionWithResponse => e
69
+ # :nocov:
70
+ e.response
71
+ # :nocov:
72
+ end
73
+
74
+ def json_safe_parse(str)
75
+ JSON.parse(str) rescue str
76
+ end
77
+ end
78
+ end
79
+
@@ -0,0 +1,5 @@
1
+ module HttpStore
2
+ class HttpLog < ActiveRecord::Base
3
+ belongs_to :requestable, polymorphic: true, optional: true
4
+ end
5
+ end
@@ -1,9 +1,11 @@
1
1
  module HttpStore
2
2
  module Requestable
3
- def build_request
4
- # callback
3
+ # will return one hash to set the request meta
4
+ def set_request
5
+ {}
5
6
  end
6
7
 
8
+ # you need rewrite this checker, when return false the request don't send
7
9
  def request_valid?
8
10
  true
9
11
  end
@@ -12,8 +14,8 @@ module HttpStore
12
14
  data_type.to_s.casecmp('json').zero?
13
15
  end
14
16
 
15
- def file_request?
16
- @data_hash.to_json.size > GRAPE_API::HTTP_FILE_SIZE_LIMIT
17
+ def uri
18
+ "#{url}?#{query_params.to_query}"
17
19
  end
18
20
 
19
21
  def get?
@@ -24,15 +26,16 @@ module HttpStore
24
26
  http_method.to_s.casecmp('post').zero?
25
27
  end
26
28
 
27
- def default_request
28
- @headers_hash ||= { charset: 'UTF-8' } # accept: :json
29
- @query_params_hash ||= {}
30
- @data_hash ||= {}
31
- @headers_hash[:content_type] = :json if json_request?
29
+ def format_request
30
+ @meta.http_method = get? ? 'GET' : 'POST' # only support get/post
32
31
 
33
- self.headers = @headers_hash.to_json
34
- self.data = @data_hash.to_json unless file_request?
35
- self.query_params = @query_params_hash.to_json
32
+ @meta.headers ||= { charset: 'UTF-8' }
33
+ @meta.headers[:content_type] = :json if json_request?
34
+
35
+ @meta.query_params ||= {}
36
+ @meta.data ||= {}
37
+
38
+ @meta.request_valid = request_valid?
36
39
  end
37
40
  end
38
41
  end
@@ -1,38 +1,29 @@
1
1
  module HttpStore
2
2
  module Responseable
3
- attr_accessor :response_obj
4
-
5
- # 判断请求是否到达第三方接口, 并处理. 若为 true 不再重复调用
3
+ # check response message is right, if is right
6
4
  def response_status_check
7
5
  status_code == 200
8
6
  end
9
7
 
10
- def json_response?
11
- response_headers_hash['content_type'].to_s =~ /json/
8
+ def response_error_handle
9
+ 'error'
12
10
  end
13
11
 
14
- def file_response?
15
- response_headers_hash['content_type'].to_s =~ /(stream|file)/
12
+ def response_success_handle
13
+ 'success'
16
14
  end
17
15
 
18
- def save_response
19
- self.status_code = response_obj.code
20
- self.response = response_obj.body if response_obj.body.size < GRAPE_API::HTTP_FILE_SIZE_LIMIT && !file_response?
21
- self.response_headers = response_obj.headers.to_json
22
- save!
16
+ def json_response?
17
+ response_headers_hash['content_type'].to_s =~ /json/
23
18
  end
24
19
 
25
- def save_response_result
26
- self.response_status = !!response_status_check
27
- @response_data_hash = response_status ? { data: rsp_success_data } : { error: rsp_error_msg }
28
- raise RestRequestError, '三方请求异常, 请与管理员联系' if result.blank?
29
-
30
- self.response_data = @response_data_hash.to_json
31
- save!
32
- end
20
+ def build_response
21
+ @meta.status_code = response_obj.code
22
+ @meta.response = json_safe_parse(response_obj.body)
23
+ @meta.response_headers = response_obj.headers
33
24
 
34
- def result
35
- response_data_hash.data.presence || response_data_hash.error.presence
25
+ @meta.response_valid = !!response_status_check
26
+ @meta.response_data = response_valid ? response_success_handle : response_error_handle
36
27
  end
37
28
  end
38
29
  end
@@ -0,0 +1,41 @@
1
+ module HttpStore
2
+ module Storable
3
+ STRING_LIMIT_SIZE = 30_000
4
+ STORE_KEYS = HttpStore::Client::META_KEYS - %w[response_obj requestable]
5
+
6
+ # you can rewrite this callback, to store the request
7
+ def store_request
8
+ return if other_params.store_class != false
9
+
10
+ (other_params.store_class || HttpStore::HttpLog).new(storable_meta).save
11
+ end
12
+
13
+ def storable_meta
14
+ @storable_meta ||= gen_storable_meta
15
+ end
16
+
17
+ def gen_storable_meta
18
+ @meta.slice(*STORE_KEYS).map do |k, v|
19
+ [k, v.is_a?(Hash) ? storable_hash(v).to_json[0..STRING_LIMIT_SIZE] : v]
20
+ end.to_h
21
+ end
22
+
23
+ def storable_hash(hash)
24
+ hash.map do |k, v|
25
+ [k, case value
26
+ when Hash
27
+ storable_hash(v)
28
+ when String
29
+ storable_string(v)
30
+ else
31
+ v
32
+ end
33
+ ]
34
+ end.to_h
35
+ end
36
+
37
+ def storable_string(str)
38
+ { digest: Digest::SHA1.hexdigest(str), origin: str[0..1000] } if str.length > STRING_LIMIT_SIZE
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module HttpStore
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/http_store.rb CHANGED
@@ -1,15 +1,21 @@
1
- require "http_store/version"
2
- require 'byebug'
3
1
  require 'active_record'
4
2
  require 'rails/engine'
5
- require 'http_store/engine'
6
3
  require 'active_support/core_ext/module'
7
4
 
5
+ require 'hashie'
6
+ require 'rest-client'
7
+
8
8
  module HttpStore
9
- class Error < StandardError; end
10
9
  extend ActiveSupport::Autoload
11
10
 
11
+ autoload :Engine
12
+ autoload :VERSION
13
+
12
14
  autoload :Requestable
13
15
  autoload :Responseable
14
- autoload :RestRequest
16
+ autoload :Storable
17
+ autoload :HttpLog
18
+ autoload :Client
19
+
20
+ class RequestError < StandardError; end
15
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - black
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-17 00:00:00.000000000 Z
11
+ date: 2019-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -58,6 +58,26 @@ dependencies:
58
58
  - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '6.1'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rails
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '5'
68
+ - - "<"
69
+ - !ruby/object:Gem::Version
70
+ version: '7'
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '5'
78
+ - - "<"
79
+ - !ruby/object:Gem::Version
80
+ version: '7'
61
81
  - !ruby/object:Gem::Dependency
62
82
  name: bundler
63
83
  requirement: !ruby/object:Gem::Requirement
@@ -131,14 +151,15 @@ files:
131
151
  - Rakefile
132
152
  - bin/console
133
153
  - bin/setup
134
- - db/migrate/1_create_rest_requests.rb
154
+ - db/migrate/1_create_http_logs.rb
135
155
  - http_store.gemspec
136
- - lib/generators/initializer_generator.rb
137
156
  - lib/http_store.rb
157
+ - lib/http_store/client.rb
138
158
  - lib/http_store/engine.rb
159
+ - lib/http_store/http_log.rb
139
160
  - lib/http_store/requestable.rb
140
161
  - lib/http_store/responseable.rb
141
- - lib/http_store/rest_request.rb
162
+ - lib/http_store/storable.rb
142
163
  - lib/http_store/version.rb
143
164
  homepage: https://github.com/308820773/http-store
144
165
  licenses: []
@@ -1,5 +0,0 @@
1
- class InitializerGenerator < Rails::Generators::Base
2
- def create_initializer_file
3
- create_file "config/initializers/initializer.rb", "# 这里是初始化文件的内容"
4
- end
5
- end
@@ -1,90 +0,0 @@
1
- # == Schema Information
2
- #
3
- # Table name: rest_requests
4
- #
5
- # id :integer not null, primary key
6
- # http_method :string(255)
7
- # url :string(255)
8
- # headers :text(65535)
9
- # query_params :text(65535)
10
- # data_type :string(255)
11
- # data :text(65535)
12
- # status_code :integer
13
- # response :text(65535)
14
- # response_headers :text(65535)
15
- # response_status :boolean
16
- # response_data :text(65535)
17
- # type :string(255)
18
- # requestable_id :string(255)
19
- # requestable_type :string(255)
20
- # created_at :datetime not null
21
- # updated_at :datetime not null
22
- # request_data :text(65535)
23
- # is_valid :boolean
24
- #
25
-
26
- module HttpStore
27
- class RestRequest < ActiveRecord::Base
28
- include HttpStore::Requestable
29
- include HttpStore::Responseable
30
-
31
- belongs_to :requestable, polymorphic: true, optional: false
32
-
33
- def self.execute(attrs, &block)
34
- req = new(attrs)
35
- req.build_request
36
- req.default_request
37
- req.is_valid = req.request_valid?
38
- req.save! # save request
39
-
40
- req.execute(&block) if req.is_valid
41
- req
42
- end
43
-
44
- def http_get_execute
45
- RestClient.get("#{url}?#{query_params_hash.to_query}", headers_hash)
46
- rescue RestClient::ExceptionWithResponse => e
47
- # :nocov:
48
- e.response
49
- # :nocov:
50
- end
51
-
52
- def http_post_execute
53
- real_data = json_request? ? data_hash.to_json : data_hash.to_hash
54
- RestClient.post("#{url}?#{query_params_hash.to_query}", real_data, headers_hash.to_hash.symbolize_keys)
55
- rescue RestClient::ExceptionWithResponse => e
56
- # :nocov:
57
- e.response
58
- # :nocov:
59
- end
60
-
61
- def execute
62
- self.response_obj = get? ? http_get_execute : http_post_execute
63
- raise RestRequestError, 'response_obj is nil' unless response_obj
64
-
65
- save_response
66
- save_response_result
67
-
68
- yield self if block_given?
69
-
70
- self
71
- end
72
-
73
- %i[query_params_hash data_hash headers_hash request_data_hash
74
- response_hash response_data_hash response_headers_hash].each do |hash_key|
75
- define_method hash_key do
76
- iv_key = "@#{hash_key}".to_sym
77
-
78
- result =
79
- if instance_variable_get(iv_key).present?
80
- instance_variable_get(iv_key)
81
- else
82
- json_field = hash_key.to_s.gsub(/_hash/, '').to_sym
83
- instance_variable_set iv_key, (JSON.parse(send(json_field)) rescue {})
84
- end
85
-
86
- Hashie::Mash.new(result) rescue Hashie::Mash.new({})
87
- end
88
- end
89
- end
90
- end