apia-client 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7855cdda856e2e80063bfb19c3c41280e3979e06de43b120e90d122768cb1144
4
+ data.tar.gz: 1ff0272215aa64ca9005f3749bcd88d681ee138ea1fb46170ed363140e8b9f27
5
+ SHA512:
6
+ metadata.gz: 60c2e8821cf3e0f96e0792d5be28b1d6feb1db85fa566094cfb587f48b16ebc0df336a72d728685c61705271ea2eb4fc9f61794b6479231f493292516067ce5f
7
+ data.tar.gz: ef94dd2485dd2a0fe28a12bd15ea915332ff544d266165677801a4ec21cda980e02f4594108680d86f62dfdffe8b97fdda4fc03b824b9f97f801efc844df9a74
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
@@ -0,0 +1,6 @@
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
4
+ require 'apia_client'
5
+
6
+ # rubocop:enable Naming/FileName
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request_types/delete'
4
+ require 'apia_client/request_types/get'
5
+ require 'apia_client/request_types/patch'
6
+ require 'apia_client/request_types/post'
7
+ require 'apia_client/request_types/put'
8
+
9
+ require 'apia_client/api'
10
+
11
+ module ApiaClient
12
+
13
+ class << self
14
+
15
+ def load(*args, **options)
16
+ API.load(*args, **options)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'apia_schema_parser'
6
+ require 'apia_client/errors/request_error'
7
+ require 'apia_client/errors/connection_error'
8
+ require 'apia_client/errors/schema_not_loaded_error'
9
+ require 'apia_client/errors/timeout_error'
10
+ require 'apia_client/response'
11
+ require 'apia_client/request_proxy'
12
+
13
+ module ApiaClient
14
+ class API
15
+
16
+ attr_reader :host
17
+ attr_reader :headers
18
+ attr_reader :schema
19
+
20
+ def initialize(host, **options)
21
+ @host = host
22
+ @headers = options[:headers] || {}
23
+ @options = options
24
+ end
25
+
26
+ def ssl?
27
+ @options[:ssl].nil? || @options[:ssl] == true
28
+ end
29
+
30
+ def port
31
+ @options[:port] || (ssl? ? 443 : 80)
32
+ end
33
+
34
+ def namespace
35
+ (@options[:namespace] || '').sub(/\A\/*/, '').sub(/\/*\z/, '')
36
+ end
37
+
38
+ def schema?
39
+ !!@schema
40
+ end
41
+
42
+ def load_schema
43
+ response = request(Get.new('schema'))
44
+ @schema = ApiaSchemaParser::Schema.new(response.hash)
45
+ true
46
+ end
47
+
48
+ def request(request)
49
+ status, headers, body = make_http_request(request) do |req|
50
+ request.add_arguments_to_request(req)
51
+ end
52
+ Response.new(self, request, body, headers, status)
53
+ end
54
+
55
+ def perform(*args)
56
+ request = create_request(*args)
57
+ return if request.nil?
58
+
59
+ yield request if block_given?
60
+ request.perform
61
+ end
62
+
63
+ def create_request(method, path)
64
+ unless schema?
65
+ raise SchemaNotLoadedError, 'No schema has been loaded for this API instance'
66
+ end
67
+
68
+ route = schema.api.route_set.routes.find do |r|
69
+ r.request_method == method.to_s.upcase &&
70
+ r.path == path
71
+ end
72
+
73
+ return if route.nil?
74
+
75
+ RequestProxy.new(self, route)
76
+ end
77
+
78
+ private
79
+
80
+ def create_http(**options)
81
+ http = Net::HTTP.new(host, port)
82
+ http.use_ssl = ssl?
83
+ http.read_timeout = options[:http_read_timeout] || @options[:http_read_timeout] || 60
84
+ http.open_timeout = options[:http_open_timeout] || @options[:http_open_timeout] || 10
85
+ http
86
+ end
87
+
88
+ def make_http_request(request)
89
+ http_request = request.class.method.new("/#{namespace}/#{request.path_for_net_http}")
90
+ @headers.each do |key, value|
91
+ http_request[key] = value
92
+ end
93
+ yield http_request if block_given?
94
+ response = make_request_with_error_handling(http_request, request)
95
+ handle_response(response)
96
+ end
97
+
98
+ def make_request_with_error_handling(http_request, request)
99
+ http = create_http(
100
+ http_read_timeout: request.http_read_timeout,
101
+ http_open_timeout: request.http_open_timeout
102
+ )
103
+ http.request(http_request)
104
+ rescue Timeout::Error => e
105
+ raise ApiaClient::TimeoutError, e.message
106
+ rescue StandardError => e
107
+ raise ConnectionError, e.message
108
+ end
109
+
110
+ def handle_response(response)
111
+ if response['content-type'] =~ /application\/json/
112
+ body = JSON.parse(response.body)
113
+ else
114
+ body = response.body
115
+ end
116
+
117
+ status_code = response.code.to_i
118
+ if status_code >= 200 && status_code < 300
119
+ return [status_code, response.to_hash, body]
120
+ end
121
+
122
+ raise RequestError.new(self, status_code, body)
123
+ end
124
+
125
+ class << self
126
+
127
+ def load(*args, **options)
128
+ api = new(*args, **options)
129
+ api.load_schema
130
+ api
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+ class ConnectionError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+ class RequestError < StandardError
5
+
6
+ attr_reader :status
7
+ attr_reader :body
8
+
9
+ # rubocop:disable Lint/MissingSuper
10
+ def initialize(client, status, body)
11
+ @client = client
12
+ @status = status
13
+ @body = body
14
+
15
+ @error = @body['error']
16
+ end
17
+ # rubocop:enable Lint/MissingSuper
18
+
19
+ def to_s
20
+ string = ["[#{@status}]"]
21
+ if code && description
22
+ string << "#{code}: #{description}"
23
+ elsif code
24
+ string << code
25
+ else
26
+ string << @body
27
+ end
28
+ string.join(' ')
29
+ end
30
+
31
+ def code
32
+ return if @error.nil?
33
+
34
+ @error['code']
35
+ end
36
+
37
+ def description
38
+ return if @error.nil?
39
+
40
+ @error['description']
41
+ end
42
+
43
+ def detail
44
+ return if @error.nil?
45
+
46
+ @error['detail'] || {}
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+ class SchemaNotLoadedError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/errors/connection_error'
4
+
5
+ module ApiaClient
6
+ class TimeoutError < ConnectionError
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+
5
+ module ApiaClient
6
+ class Request
7
+
8
+ class << self
9
+
10
+ attr_accessor :method
11
+
12
+ end
13
+
14
+ attr_reader :path
15
+ attr_reader :arguments
16
+ attr_accessor :http_read_timeout
17
+ attr_accessor :http_open_timeout
18
+
19
+ def initialize(path)
20
+ @path = path
21
+ @arguments = {}
22
+ end
23
+
24
+ def path_for_net_http
25
+ path
26
+ end
27
+
28
+ def add_arguments_to_request(request)
29
+ request['Content-Type'] = 'application/json'
30
+ request.body = arguments.to_json
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+ class RequestProxy
5
+
6
+ METHOD_MAP = {
7
+ get: ApiaClient::Get,
8
+ post: ApiaClient::Post,
9
+ patch: ApiaClient::Patch,
10
+ put: ApiaClient::Put,
11
+ delete: ApiaClient::Delete
12
+ }.freeze
13
+
14
+ attr_reader :route
15
+ attr_reader :request
16
+
17
+ def initialize(client, route)
18
+ @client = client
19
+ @route = route
20
+
21
+ request_class = METHOD_MAP[@route.request_method.downcase.to_sym]
22
+ @request = request_class.new(@route.path)
23
+ end
24
+
25
+ def perform
26
+ @client.request(@request)
27
+ end
28
+
29
+ def arguments
30
+ @request.arguments
31
+ end
32
+
33
+ def endpoint
34
+ @route.endpoint
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request'
4
+
5
+ module ApiaClient
6
+ class Delete < Request
7
+
8
+ self.method = Net::HTTP::Delete
9
+
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module ApiaClient
8
+ class Get < Request
9
+
10
+ self.method = Net::HTTP::Get
11
+
12
+ def path_for_net_http
13
+ querystring = URI.encode_www_form(_arguments: @arguments.to_json)
14
+ "#{path}?#{querystring}"
15
+ end
16
+
17
+ def add_arguments_to_request(request)
18
+ # Don't need to do anything for GET requests...
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request'
4
+
5
+ module ApiaClient
6
+ class Patch < Request
7
+
8
+ self.method = Net::HTTP::Patch
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request'
4
+
5
+ module ApiaClient
6
+ class Post < Request
7
+
8
+ self.method = Net::HTTP::Post
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'apia_client/request'
4
+
5
+ module ApiaClient
6
+ class Put < Request
7
+
8
+ self.method = Net::HTTP::Put
9
+
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+ class Response
5
+
6
+ def initialize(client, request, hash, headers, status)
7
+ @client = client
8
+ @request = request
9
+ @hash = hash
10
+ @headers = headers
11
+ @status = status
12
+ end
13
+
14
+ attr_reader :request
15
+ attr_reader :hash
16
+ attr_reader :headers
17
+ attr_reader :status
18
+
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiaClient
4
+
5
+ VERSION_FILE_ROOT = File.expand_path('../../VERSION', __dir__)
6
+ if File.file?(VERSION_FILE_ROOT)
7
+ VERSION = File.read(VERSION_FILE_ROOT).strip.sub(/\Av/, '')
8
+ else
9
+ VERSION = '0.0.0.dev'
10
+ end
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apia-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Cooke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: apia-schema-parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A client library for talking to any Apia API.
42
+ email:
43
+ - adam@k.io
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - VERSION
49
+ - lib/apia-client.rb
50
+ - lib/apia_client.rb
51
+ - lib/apia_client/api.rb
52
+ - lib/apia_client/errors/connection_error.rb
53
+ - lib/apia_client/errors/request_error.rb
54
+ - lib/apia_client/errors/schema_not_loaded_error.rb
55
+ - lib/apia_client/errors/timeout_error.rb
56
+ - lib/apia_client/request.rb
57
+ - lib/apia_client/request_proxy.rb
58
+ - lib/apia_client/request_types/delete.rb
59
+ - lib/apia_client/request_types/get.rb
60
+ - lib/apia_client/request_types/patch.rb
61
+ - lib/apia_client/request_types/post.rb
62
+ - lib/apia_client/request_types/put.rb
63
+ - lib/apia_client/response.rb
64
+ - lib/apia_client/version.rb
65
+ homepage: https://github.com/krystal/apia-ruby-client
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '2.5'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.1.6
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: A client library for talking to any Apia API.
88
+ test_files: []