crapi 0.1.3 → 1.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 +4 -4
- data/.circleci/config.yml +63 -0
- data/.rubocop.yml +53 -70
- data/.ruby-version +1 -1
- data/Gemfile.lock +66 -42
- data/README.md +29 -27
- data/crapi.gemspec +15 -15
- data/docs/{Crapi → CrAPI}/ArgumentError.html +15 -16
- data/docs/{Crapi → CrAPI}/BadHttpResponseError.html +15 -16
- data/docs/{Crapi → CrAPI}/Client.html +144 -174
- data/docs/{Crapi → CrAPI}/Error.html +14 -15
- data/docs/{Crapi → CrAPI}/Proxy.html +65 -89
- data/docs/CrAPI.html +157 -0
- data/docs/Net/HTTP.html +18 -23
- data/docs/_index.html +19 -19
- data/docs/class_list.html +3 -3
- data/docs/css/style.css +7 -9
- data/docs/file.README.html +68 -87
- data/docs/file_list.html +2 -2
- data/docs/frames.html +2 -2
- data/docs/index.html +68 -87
- data/docs/js/app.js +69 -3
- data/docs/method_list.html +34 -34
- data/docs/top-level-namespace.html +8 -8
- data/lib/crapi/client.rb +224 -228
- data/lib/crapi/errors.rb +7 -7
- data/lib/crapi/proxy.rb +82 -82
- data/lib/crapi/version.rb +10 -10
- data/lib/crapi.rb +3 -1
- data/spec/crapi_client_spec.rb +121 -0
- data/spec/crapi_errors_spec.rb +17 -0
- data/spec/crapi_proxy_spec.rb +121 -0
- data/spec/crapi_spec.rb +5 -0
- data/spec/spec_helper.rb +19 -0
- metadata +66 -52
- data/.travis.yml +0 -5
- data/docs/Crapi.html +0 -153
data/lib/crapi/client.rb
CHANGED
@@ -5,60 +5,60 @@ require 'openssl'
|
|
5
5
|
require 'crapi/proxy'
|
6
6
|
require 'crapi/errors'
|
7
7
|
|
8
|
-
module
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
module CrAPI
|
9
|
+
# Provides a connection mechanism, simple CRUD methods ({#delete} / {#get} / {#patch} / {#post} /
|
10
|
+
# {#put}), and proxy generators.
|
11
|
+
#
|
12
12
|
class Client
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
# A Hash containing headers to send with every request (unless overriden elsewhere). Headers
|
14
|
+
# set by the user via the CRUD methods' *headers* still override any conflicting default
|
15
|
+
# header.
|
16
|
+
#
|
17
17
|
attr_accessor :default_headers
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# The content-type for JSON data.
|
20
|
+
#
|
21
21
|
JSON_CONTENT_TYPE = 'application/json'.freeze
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
# The content-type for FORM data.
|
24
|
+
#
|
25
25
|
FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded'.freeze
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
27
|
+
# @param base_uri [URI, String]
|
28
|
+
# The base URI the client should use for determining the host to connect to, determining
|
29
|
+
# whether SSH is applicable, and setting the base path for subsequent CRUD calls.
|
30
|
+
#
|
31
|
+
# @param opts [Hash]
|
32
|
+
# Method options. All method options are **optional** in this particular case.
|
33
|
+
#
|
34
|
+
# @option opts [true, false] :insecure
|
35
|
+
# Whether to allow insecure SSH connections (i.e. don't attempt to verify the validity of the
|
36
|
+
# given certificate).
|
37
|
+
#
|
38
|
+
# @option opts [String] :proxy_host
|
39
|
+
# The DNS name or IP address of a proxy server to use when connecting to the target system.
|
40
|
+
# Maps to `Net::HTTP#new`'s *p_addr*.
|
41
|
+
#
|
42
|
+
# @option opts [Number] :proxy_port
|
43
|
+
# The proxy server port to use when connecting to the target system.
|
44
|
+
# Maps to `Net::HTTP#new`'s *p_port*.
|
45
|
+
#
|
46
|
+
# @option opts [String] :proxy_username
|
47
|
+
# The username to give if authorization is required to access the specified proxy host.
|
48
|
+
# Maps to `Net::HTTP#new`'s *p_user*.
|
49
|
+
#
|
50
|
+
# @option opts [Number] :proxy_password
|
51
|
+
# The password to give if authorization is required to access the specified proxy host.
|
52
|
+
# Maps to `Net::HTTP#new`'s *p_pass*.
|
53
|
+
#
|
54
|
+
#
|
55
|
+
# @raise [CrAPI::ArgumentError]
|
56
|
+
#
|
57
57
|
def initialize(base_uri, opts = {})
|
58
58
|
@base_uri = case base_uri
|
59
59
|
when URI then base_uri
|
60
60
|
when String then URI(base_uri)
|
61
|
-
else raise
|
61
|
+
else raise CrAPI::ArgumentError, %(Unexpected "base_uri" type: #{base_uri.class})
|
62
62
|
end
|
63
63
|
|
64
64
|
@proxy_host = opts[:proxy_host]
|
@@ -74,41 +74,41 @@ module Crapi
|
|
74
74
|
@default_headers = { 'Content-Type': JSON_CONTENT_TYPE }.with_indifferent_access
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
77
|
+
# Returns a new {CrAPI::Proxy CrAPI::Proxy} for this client.
|
78
|
+
#
|
79
|
+
#
|
80
|
+
# @param segment [String]
|
81
|
+
# The segment to add to this client's path.
|
82
|
+
#
|
83
|
+
# @param headers [Hash]
|
84
|
+
# The default headers for the new proxy.
|
85
|
+
#
|
86
|
+
#
|
87
|
+
# @return [CrAPI::Proxy]
|
88
|
+
#
|
89
89
|
def new_proxy(segment = '/', headers: nil)
|
90
90
|
Proxy.new(add: segment, to: self, headers: headers)
|
91
91
|
end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
93
|
+
# CRUD methods ...
|
94
|
+
|
95
|
+
# CRUD method: DELETE
|
96
|
+
#
|
97
|
+
# @param path [String]
|
98
|
+
# The path to the resource to DELETE. Note that this path is always interpreted as relative
|
99
|
+
# to the client's base_uri's path, regardless of whether it begins with a "/".
|
100
|
+
#
|
101
|
+
# @param headers [Hash]
|
102
|
+
# Additional headers to set in addition to the client's defaults. Any header given here and
|
103
|
+
# also appearing in the client's defaults will override said default value.
|
104
|
+
#
|
105
|
+
# @param query [Hash, Array, String]
|
106
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
107
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
108
|
+
#
|
109
|
+
#
|
110
|
+
# @return [Object]
|
111
|
+
#
|
112
112
|
def delete(path, headers: {}, query: {})
|
113
113
|
headers = @default_headers.merge(headers)
|
114
114
|
|
@@ -117,23 +117,23 @@ module Crapi
|
|
117
117
|
parse_response(response)
|
118
118
|
end
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
120
|
+
# CRUD method: GET
|
121
|
+
#
|
122
|
+
# @param path [String]
|
123
|
+
# The path to the resource to GET. Note that this path is always interpreted as relative to
|
124
|
+
# the client's base_uri's path, regardless of whether it begins with a "/".
|
125
|
+
#
|
126
|
+
# @param headers [Hash]
|
127
|
+
# Additional headers to set in addition to the client's defaults. Any header given here and
|
128
|
+
# also appearing in the client's defaults will override said default value.
|
129
|
+
#
|
130
|
+
# @param query [Hash, Array, String]
|
131
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
132
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
133
|
+
#
|
134
|
+
#
|
135
|
+
# @return [Object]
|
136
|
+
#
|
137
137
|
def get(path, headers: {}, query: {})
|
138
138
|
headers = @default_headers.merge(headers)
|
139
139
|
|
@@ -142,27 +142,27 @@ module Crapi
|
|
142
142
|
parse_response(response)
|
143
143
|
end
|
144
144
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
145
|
+
# CRUD method: PATCH
|
146
|
+
#
|
147
|
+
# @param path [String]
|
148
|
+
# The path to the resource to PATCH. Note that this path is always interpreted as relative to
|
149
|
+
# the client's base_uri's path, regardless of whether it begins with a "/".
|
150
|
+
#
|
151
|
+
# @param headers [Hash]
|
152
|
+
# Additional headers to set in addition to the client's defaults. Any header given here and
|
153
|
+
# also appearing in the client's defaults will override said default value.
|
154
|
+
#
|
155
|
+
# @param query [Hash, Array, String]
|
156
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
157
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
158
|
+
#
|
159
|
+
# @param payload [Hash, String]
|
160
|
+
# The payload to send, if any. Strings are used as-is; Hashes are serialized per the
|
161
|
+
# request's "Content-Type" header.
|
162
|
+
#
|
163
|
+
#
|
164
|
+
# @return [Object]
|
165
|
+
#
|
166
166
|
def patch(path, headers: {}, query: {}, payload: {})
|
167
167
|
headers = @default_headers.merge(headers)
|
168
168
|
payload = format_payload(payload, as: headers[:'Content-Type'])
|
@@ -172,27 +172,27 @@ module Crapi
|
|
172
172
|
parse_response(response)
|
173
173
|
end
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
175
|
+
# CRUD method: POST
|
176
|
+
#
|
177
|
+
# @param path [String]
|
178
|
+
# The path to the resource to POST. Note that this path is always interpreted as relative to
|
179
|
+
# the client's base_uri's path, regardless of whether it begins with a "/".
|
180
|
+
#
|
181
|
+
# @param headers [Hash]
|
182
|
+
# Additional headers to set in addition to the client's defaults. Any header given here and
|
183
|
+
# also appearing in the client's defaults will override said default value.
|
184
|
+
#
|
185
|
+
# @param query [Hash, Array, String]
|
186
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
187
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
188
|
+
#
|
189
|
+
# @param payload [Hash, String]
|
190
|
+
# The payload to send, if any. Strings are used as-is; Hashes are serialized per the
|
191
|
+
# request's "Content-Type" header.
|
192
|
+
#
|
193
|
+
#
|
194
|
+
# @return [Object]
|
195
|
+
#
|
196
196
|
def post(path, headers: {}, query: {}, payload: {})
|
197
197
|
headers = @default_headers.merge(headers)
|
198
198
|
payload = format_payload(payload, as: headers[:'Content-Type'])
|
@@ -202,27 +202,27 @@ module Crapi
|
|
202
202
|
parse_response(response)
|
203
203
|
end
|
204
204
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
205
|
+
# CRUD method: PUT
|
206
|
+
#
|
207
|
+
# @param path [String]
|
208
|
+
# The path to the resource to PATCH. Note that this path is always interpreted as relative to
|
209
|
+
# the client's base_uri's path, regardless of whether it begins with a "/".
|
210
|
+
#
|
211
|
+
# @param headers [Hash]
|
212
|
+
# Additional headers to set in addition to the client's defaults. Any header given here and
|
213
|
+
# also appearing in the client's defaults will override said default value.
|
214
|
+
#
|
215
|
+
# @param query [Hash, Array, String]
|
216
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
217
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
218
|
+
#
|
219
|
+
# @param payload [Hash, String]
|
220
|
+
# The payload to send, if any. Strings are used as-is; Hashes are serialized per the
|
221
|
+
# request's "Content-Type" header.
|
222
|
+
#
|
223
|
+
#
|
224
|
+
# @return [Object]
|
225
|
+
#
|
226
226
|
def put(path, headers: {}, query: {}, payload: {})
|
227
227
|
headers = @default_headers.merge(headers)
|
228
228
|
payload = format_payload(payload, as: headers[:'Content-Type'])
|
@@ -232,27 +232,23 @@ module Crapi
|
|
232
232
|
parse_response(response)
|
233
233
|
end
|
234
234
|
|
235
|
-
##
|
236
|
-
|
237
235
|
private
|
238
236
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
## @return [String]
|
255
|
-
##
|
237
|
+
# Assembles a path and a query string Hash/Array/String into a URI path.
|
238
|
+
#
|
239
|
+
#
|
240
|
+
# @param path [String]
|
241
|
+
# The path to the desired resource.
|
242
|
+
#
|
243
|
+
# @param query [Hash, Array, String]
|
244
|
+
# Query string values, if any, to append to the given path. Strings are appended as-is;
|
245
|
+
# Hashes and Arrays are serialized as URI-encoded form data before appending.
|
246
|
+
#
|
247
|
+
#
|
248
|
+
# @raise [CrAPI::ArgumentError]
|
249
|
+
#
|
250
|
+
# @return [String]
|
251
|
+
#
|
256
252
|
def full_path(path, query: {})
|
257
253
|
path = [@base_uri.path, path].map { |i| i.gsub(%r{^/|/$}, '') }.keep_if(&:present?)
|
258
254
|
path = "/#{path.join('/')}"
|
@@ -261,51 +257,51 @@ module Crapi
|
|
261
257
|
path += case query
|
262
258
|
when Hash, Array then "?#{URI.encode_www_form(query)}"
|
263
259
|
when String then "?#{query}"
|
264
|
-
else raise
|
260
|
+
else raise CrAPI::ArgumentError, %(Unexpected "query" type: #{query.class})
|
265
261
|
end
|
266
262
|
end
|
267
263
|
|
268
264
|
path
|
269
265
|
end
|
270
266
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
267
|
+
# Verifies the given value is that of a successful HTTP response.
|
268
|
+
#
|
269
|
+
#
|
270
|
+
# @param response [Net::HTTPResponse]
|
271
|
+
# The response to evaluate as "successful" or not.
|
272
|
+
#
|
273
|
+
#
|
274
|
+
# @raise [CrAPI::BadHttpResponseError]
|
275
|
+
#
|
276
|
+
# @return [nil]
|
277
|
+
#
|
282
278
|
def ensure_success!(response)
|
283
279
|
return if response.is_a? Net::HTTPSuccess
|
284
280
|
|
285
281
|
message = "#{response.code} - #{response.message}"
|
286
282
|
message += "\n#{response.body}" if response.body.present?
|
287
283
|
|
288
|
-
raise
|
284
|
+
raise CrAPI::BadHttpResponseError, message
|
289
285
|
end
|
290
286
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
287
|
+
# Serializes the given payload per the requested content-type.
|
288
|
+
#
|
289
|
+
#
|
290
|
+
# @param payload [Hash, String]
|
291
|
+
# The payload to format. Strings are returned as-is; Hashes are serialized per the given *as*
|
292
|
+
# content-type.
|
293
|
+
#
|
294
|
+
# @param as [String]
|
295
|
+
# The target content-type.
|
296
|
+
#
|
297
|
+
#
|
298
|
+
# @return [String]
|
299
|
+
#
|
304
300
|
def format_payload(payload, as: JSON_CONTENT_TYPE)
|
305
|
-
|
301
|
+
# Non-Hash payloads are passed through as-is.
|
306
302
|
return payload unless payload.is_a? Hash
|
307
303
|
|
308
|
-
|
304
|
+
# Massage Hash-like payloads into a suitable format.
|
309
305
|
case as
|
310
306
|
when JSON_CONTENT_TYPE
|
311
307
|
JSON.generate(payload.as_json)
|
@@ -316,15 +312,15 @@ module Crapi
|
|
316
312
|
end
|
317
313
|
end
|
318
314
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
315
|
+
# Parses the given response as its claimed content-type.
|
316
|
+
#
|
317
|
+
#
|
318
|
+
# @param response [Net::HTTPResponse]
|
319
|
+
# The response whose body is to be parsed.
|
320
|
+
#
|
321
|
+
#
|
322
|
+
# @return [Object]
|
323
|
+
#
|
328
324
|
def parse_response(response)
|
329
325
|
case response.content_type
|
330
326
|
when JSON_CONTENT_TYPE
|
@@ -335,25 +331,25 @@ module Crapi
|
|
335
331
|
end
|
336
332
|
end
|
337
333
|
|
338
|
-
|
339
|
-
|
334
|
+
# Net::HTTP needs a shortcut instance method for PUT calls like it does for GET/DELETE/PATCH/POST.
|
335
|
+
#
|
340
336
|
class Net::HTTP
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
337
|
+
# Convenience PUT method monkey-patched into Net::HTTP.
|
338
|
+
#
|
339
|
+
# Net::HTTP provides handy methods for DELETE, GET, HEAD, OPTIONS, PATCH, and POST, **but not
|
340
|
+
# PUT**, so we have to monkey-patch one in. The parameters listed below were chosen to match
|
341
|
+
# those in use for the other Net::HTTP request methods in both name and meaning.
|
342
|
+
#
|
343
|
+
#
|
344
|
+
# @param path [String]
|
345
|
+
# @param data [String]
|
346
|
+
# @param initheader [Hash]
|
347
|
+
# @param dest [nil]
|
348
|
+
#
|
349
|
+
#
|
350
|
+
# @return [Net::HTTPResponse]
|
351
|
+
#
|
352
|
+
# @see https://docs.ruby-lang.org/en/trunk/Net/HTTP.html
|
357
353
|
def put(path, data, initheader = nil, dest = nil, &block)
|
358
354
|
send_entity(path, data, initheader, dest, Put, &block)
|
359
355
|
end
|
data/lib/crapi/errors.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
1
|
+
module CrAPI
|
2
|
+
# The base Error class for all {CrAPI}-related issues.
|
3
|
+
#
|
4
4
|
class Error < ::StandardError
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
# An error relating to missing, invalid, or incompatible method arguments.
|
8
|
+
#
|
9
9
|
class ArgumentError < Error
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
# An error relating to a 4XX/5XX HTTP response code.
|
13
|
+
#
|
14
14
|
class BadHttpResponseError < Error
|
15
15
|
end
|
16
16
|
end
|