restify 1.7.0 → 1.8.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/CHANGELOG.md +4 -0
- data/README.md +4 -2
- data/lib/restify/adapter/em.rb +4 -2
- data/lib/restify/adapter/pooled_em.rb +1 -1
- data/lib/restify/adapter/typhoeus.rb +31 -10
- data/lib/restify/context.rb +2 -1
- data/lib/restify/error.rb +0 -2
- data/lib/restify/global.rb +1 -3
- data/lib/restify/logging.rb +19 -0
- data/lib/restify/processors/base.rb +0 -4
- data/lib/restify/promise.rb +0 -1
- data/lib/restify/relation.rb +4 -1
- data/lib/restify/request.rb +0 -1
- data/lib/restify/resource.rb +1 -1
- data/lib/restify/response.rb +1 -0
- data/lib/restify/version.rb +1 -1
- data/spec/restify/context_spec.rb +1 -1
- data/spec/restify/features/head_requests_spec.rb +42 -0
- data/spec/restify/features/request_headers_spec.rb +5 -5
- data/spec/restify/timeout_spec.rb +8 -8
- data/spec/restify_spec.rb +12 -12
- data/spec/spec_helper.rb +6 -4
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6209f25a9b9d70898ee86458568d669ee588dd7d01a0918855ca39c6995332dd
|
4
|
+
data.tar.gz: 32e35cd463f1ce87d76cf0ded3bcf3f8266f305a5d10aafbc62fb47ff3145315
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb70a7e9edb83c76074566b8607c9439b585b8c95925806a84b343dee96872f2d497fb96edf2120109c8cbcc337a141c8c6447ad35ed88b83c51dddcdb2cb0c0
|
7
|
+
data.tar.gz: 38cc84e8835134df693ef1161cf1696d15823e28077d5c5c4214c939298db79a01127c3147fe1f9ecdbce08de5a782a592da2bc7d9bfc79afdb7e70d194f0324
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Restify
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/jgraichen/restify)
|
4
|
+
|
5
|
+
Restify is an hypermedia REST client that does parallel, concurrent and keep-alive requests by default.
|
4
6
|
|
5
7
|
Restify scans Link headers and returned resource for links and relations to other resources, represented as RFC6570 URI Templates, and exposes those to the developer.
|
6
8
|
|
@@ -121,7 +123,7 @@ See commented example in main spec [`spec/restify_spec.rb`](https://github.com/j
|
|
121
123
|
|
122
124
|
## License
|
123
125
|
|
124
|
-
Copyright (C) 2014-
|
126
|
+
Copyright (C) 2014-2018 Jan Graichen
|
125
127
|
|
126
128
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
127
129
|
|
data/lib/restify/adapter/em.rb
CHANGED
@@ -37,6 +37,7 @@ module Restify
|
|
37
37
|
requests << [request, writer, retried]
|
38
38
|
end
|
39
39
|
end
|
40
|
+
# rubocop:enable all
|
40
41
|
|
41
42
|
def connection
|
42
43
|
@connection ||= EventMachine::HttpRequest.new(origin)
|
@@ -101,12 +102,13 @@ module Restify
|
|
101
102
|
else
|
102
103
|
begin
|
103
104
|
raise "(#{req.response_header.status}) #{req.error}"
|
104
|
-
rescue => e
|
105
|
+
rescue StandardError => e
|
105
106
|
writer.reject e
|
106
107
|
end
|
107
108
|
end
|
108
109
|
end
|
109
110
|
end
|
111
|
+
# rubocop:enable all
|
110
112
|
end
|
111
113
|
|
112
114
|
def call_native(request, writer)
|
@@ -128,7 +130,7 @@ module Restify
|
|
128
130
|
Thread.new do
|
129
131
|
begin
|
130
132
|
EventMachine.run {}
|
131
|
-
rescue => e
|
133
|
+
rescue StandardError => e
|
132
134
|
puts "#{self.class} -> #{e}\n#{e.backtrace.join("\n")}"
|
133
135
|
raise e
|
134
136
|
end
|
@@ -27,6 +27,8 @@ module Restify
|
|
27
27
|
@sync
|
28
28
|
end
|
29
29
|
|
30
|
+
# rubocop:disable AbcSize
|
31
|
+
# rubocop:disable MethodLength
|
30
32
|
def call_native(request, writer)
|
31
33
|
req = convert(request, writer)
|
32
34
|
|
@@ -34,20 +36,28 @@ module Restify
|
|
34
36
|
req.run
|
35
37
|
else
|
36
38
|
@mutex.synchronize do
|
37
|
-
|
39
|
+
debug 'request:add',
|
40
|
+
tag: request.object_id,
|
41
|
+
method: request.method.upcase,
|
42
|
+
url: request.uri
|
43
|
+
|
38
44
|
@hydra.queue(req)
|
39
45
|
@hydra.dequeue_many
|
40
46
|
|
41
47
|
thread.run unless thread.status
|
42
48
|
end
|
43
49
|
|
44
|
-
|
50
|
+
debug 'request:signal', tag: request.object_id
|
51
|
+
|
45
52
|
@signal.signal
|
46
53
|
end
|
47
54
|
end
|
55
|
+
# rubocop:enable all
|
48
56
|
|
49
57
|
private
|
50
58
|
|
59
|
+
# rubocop:disable AbcSize
|
60
|
+
# rubocop:disable MethodLength
|
51
61
|
def convert(request, writer)
|
52
62
|
::Typhoeus::Request.new(
|
53
63
|
request.uri,
|
@@ -59,18 +69,22 @@ module Restify
|
|
59
69
|
connecttimeout: request.timeout
|
60
70
|
).tap do |req|
|
61
71
|
req.on_complete do |response|
|
62
|
-
|
72
|
+
debug 'request:complete',
|
73
|
+
tag: request.object_id,
|
74
|
+
status: response.code
|
63
75
|
|
64
76
|
if response.timed_out?
|
65
77
|
writer.reject Restify::Timeout.new request
|
66
|
-
elsif response.code
|
67
|
-
writer.reject
|
78
|
+
elsif response.code.zero?
|
79
|
+
writer.reject \
|
80
|
+
Restify::NetworkError.new(request, response.return_message)
|
68
81
|
else
|
69
82
|
writer.fulfill convert_back(response, request)
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
73
86
|
end
|
87
|
+
# rubocop:enable all
|
74
88
|
|
75
89
|
def convert_back(response, request)
|
76
90
|
uri = request.uri
|
@@ -92,7 +106,8 @@ module Restify
|
|
92
106
|
def thread
|
93
107
|
if @thread.nil? || !@thread.status
|
94
108
|
# Recreate thread if nil or dead
|
95
|
-
|
109
|
+
debug 'hydra:spawn'
|
110
|
+
|
96
111
|
@thread = Thread.new { _loop }
|
97
112
|
end
|
98
113
|
|
@@ -108,21 +123,27 @@ module Restify
|
|
108
123
|
@hydra.queued_requests.any? || @hydra.multi.easy_handles.any?
|
109
124
|
end
|
110
125
|
|
126
|
+
# rubocop:disable MethodLength
|
111
127
|
def _run
|
112
|
-
|
128
|
+
debug 'hydra:run'
|
113
129
|
@hydra.run while _ongoing?
|
114
|
-
|
130
|
+
debug 'hydra:completed'
|
115
131
|
|
116
132
|
@mutex.synchronize do
|
117
133
|
return if _ongoing?
|
118
134
|
|
119
|
-
|
135
|
+
debug 'hydra:pause'
|
120
136
|
@signal.wait(@mutex, 60)
|
121
|
-
|
137
|
+
debug 'hydra:resumed'
|
122
138
|
end
|
123
139
|
rescue StandardError => e
|
124
140
|
logger.error(e)
|
125
141
|
end
|
142
|
+
# rubocop:enable all
|
143
|
+
|
144
|
+
def _log_prefix
|
145
|
+
"[#{object_id}/#{Thread.current.object_id}]"
|
146
|
+
end
|
126
147
|
end
|
127
148
|
end
|
128
149
|
end
|
data/lib/restify/context.rb
CHANGED
@@ -35,7 +35,7 @@ module Restify
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def inherit(uri, **kwargs)
|
38
|
-
uri
|
38
|
+
uri ||= self.uri
|
39
39
|
Context.new uri, kwargs.merge(options)
|
40
40
|
end
|
41
41
|
|
@@ -66,6 +66,7 @@ module Restify
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
+
# rubocop:enable all
|
69
70
|
|
70
71
|
def encode_with(coder)
|
71
72
|
coder.map = marshal_dump
|
data/lib/restify/error.rb
CHANGED
data/lib/restify/global.rb
CHANGED
data/lib/restify/logging.rb
CHANGED
@@ -7,5 +7,24 @@ module Restify
|
|
7
7
|
def logger
|
8
8
|
@logger ||= ::Logging.logger[self]
|
9
9
|
end
|
10
|
+
|
11
|
+
def debug(message = nil, tag: nil, **kwargs)
|
12
|
+
logger.debug do
|
13
|
+
[
|
14
|
+
_log_prefix,
|
15
|
+
*Array(tag),
|
16
|
+
message,
|
17
|
+
_fmt(**kwargs)
|
18
|
+
].map(&:to_s).reject(&:empty?).join(' ')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def _log_prefix
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def _fmt(**kwargs)
|
27
|
+
kwargs.each.map {|k, v| "#{k}=#{v}" }.join(' ')
|
28
|
+
end
|
10
29
|
end
|
11
30
|
end
|
data/lib/restify/promise.rb
CHANGED
data/lib/restify/relation.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Restify
|
4
|
-
#
|
5
4
|
class Relation
|
6
5
|
# Relation context
|
7
6
|
#
|
@@ -28,6 +27,10 @@ module Restify
|
|
28
27
|
request :get, nil, params, opts
|
29
28
|
end
|
30
29
|
|
30
|
+
def head(params = {}, opts = {})
|
31
|
+
request :head, nil, params, opts
|
32
|
+
end
|
33
|
+
|
31
34
|
def delete(params = {}, opts = {})
|
32
35
|
request :delete, nil, params, opts
|
33
36
|
end
|
data/lib/restify/request.rb
CHANGED
data/lib/restify/resource.rb
CHANGED
data/lib/restify/response.rb
CHANGED
data/lib/restify/version.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Restify do
|
6
|
+
let!(:request_stub) do
|
7
|
+
stub_request(:head, 'http://localhost/base')
|
8
|
+
.with(query: hash_including({}))
|
9
|
+
.to_return do
|
10
|
+
<<-RESPONSE.gsub(/^ {8}/, '')
|
11
|
+
HTTP/1.1 200 OK
|
12
|
+
Content-Length: 333
|
13
|
+
Transfer-Encoding: chunked
|
14
|
+
Link: <http://localhost/other>; rel="neat"
|
15
|
+
RESPONSE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'HEAD requests' do
|
20
|
+
subject { Restify.new('http://localhost/base').head(params).value! }
|
21
|
+
let(:params) { {} }
|
22
|
+
|
23
|
+
it 'returns a resource with access to headers' do
|
24
|
+
expect(subject.response.headers).to include('CONTENT_LENGTH' => '333')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'parses Link headers into relations' do
|
28
|
+
expect(subject).to have_relation :neat
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with params' do
|
32
|
+
let(:params) { {foo: 'bar'} }
|
33
|
+
|
34
|
+
it 'adds them to the query string' do
|
35
|
+
subject
|
36
|
+
expect(
|
37
|
+
request_stub.with(query: {foo: 'bar'})
|
38
|
+
).to have_been_requested
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -5,14 +5,14 @@ require 'spec_helper'
|
|
5
5
|
describe Restify do
|
6
6
|
let!(:request_stub) do
|
7
7
|
stub_request(:get, 'http://localhost/base').to_return do
|
8
|
-
<<-
|
8
|
+
<<-RESPONSE.gsub(/^ {8}/, '')
|
9
9
|
HTTP/1.1 200 OK
|
10
10
|
Content-Type: application/json
|
11
11
|
Transfer-Encoding: chunked
|
12
12
|
Link: <http://localhost/base>; rel="self"
|
13
13
|
|
14
14
|
{ "response": "success" }
|
15
|
-
|
15
|
+
RESPONSE
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -22,7 +22,7 @@ describe Restify do
|
|
22
22
|
it 'sends the headers only for that request' do
|
23
23
|
root = context.get(
|
24
24
|
{},
|
25
|
-
headers: {'Accept' => 'application/msgpack, application/json'}
|
25
|
+
{headers: {'Accept' => 'application/msgpack, application/json'}}
|
26
26
|
).value!
|
27
27
|
|
28
28
|
root.rel(:self).get.value!
|
@@ -55,7 +55,7 @@ describe Restify do
|
|
55
55
|
it 'can overwrite headers for single requests' do
|
56
56
|
root = context.get(
|
57
57
|
{},
|
58
|
-
headers: {'Accept' => 'application/xml'}
|
58
|
+
{headers: {'Accept' => 'application/xml'}}
|
59
59
|
).value!
|
60
60
|
|
61
61
|
root.rel(:self).get.value!
|
@@ -71,7 +71,7 @@ describe Restify do
|
|
71
71
|
it 'can add additional headers for single requests' do
|
72
72
|
root = context.get(
|
73
73
|
{},
|
74
|
-
headers: {'X-Custom' => 'foobar'}
|
74
|
+
{headers: {'X-Custom' => 'foobar'}}
|
75
75
|
).value!
|
76
76
|
|
77
77
|
root.rel(:self).get.value!
|
@@ -23,32 +23,32 @@ describe Restify::Timeout do
|
|
23
23
|
|
24
24
|
describe '#wait_on!' do
|
25
25
|
it 'calls block on IVar timeout' do
|
26
|
-
expect
|
26
|
+
expect do
|
27
27
|
timer.wait_on!(Concurrent::IVar.new)
|
28
|
-
|
28
|
+
end.to raise_error ::Restify::Timeout::Error
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'calls block on Promise timeout' do
|
32
|
-
expect
|
32
|
+
expect do
|
33
33
|
timer.wait_on!(Restify::Promise.new)
|
34
|
-
|
34
|
+
end.to raise_error ::Restify::Timeout::Error
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'does nothing on successful IVar' do
|
38
|
-
expect
|
38
|
+
expect do
|
39
39
|
Concurrent::IVar.new.tap do |ivar|
|
40
40
|
Thread.new { ivar.set :success }
|
41
41
|
expect(timer.wait_on!(ivar)).to eq :success
|
42
42
|
end
|
43
|
-
|
43
|
+
end.to_not raise_error
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'does nothing on successful Promise' do
|
47
|
-
expect
|
47
|
+
expect do
|
48
48
|
Restify::Promise.fulfilled(:success).tap do |p|
|
49
49
|
expect(timer.wait_on!(p)).to eq :success
|
50
50
|
end
|
51
|
-
|
51
|
+
end.to_not raise_error
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/spec/restify_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Restify do
|
|
6
6
|
context 'as a dynamic HATEOAS client' do
|
7
7
|
before do
|
8
8
|
stub_request(:get, 'http://localhost/base').to_return do
|
9
|
-
<<-
|
9
|
+
<<-RESPONSE.gsub(/^ {10}/, '')
|
10
10
|
HTTP/1.1 200 OK
|
11
11
|
Content-Type: application/json
|
12
12
|
Transfer-Encoding: chunked
|
@@ -18,11 +18,11 @@ describe Restify do
|
|
18
18
|
"search_url": "http://localhost/base/search?q={query}",
|
19
19
|
"mirror_url": null
|
20
20
|
}
|
21
|
-
|
21
|
+
RESPONSE
|
22
22
|
end
|
23
23
|
|
24
24
|
stub_request(:get, 'http://localhost/base/users').to_return do
|
25
|
-
<<-
|
25
|
+
<<-RESPONSE.gsub(/^ {10}/, '')
|
26
26
|
HTTP/1.1 200 OK
|
27
27
|
Content-Type: application/json
|
28
28
|
Transfer-Encoding: chunked
|
@@ -37,25 +37,25 @@ describe Restify do
|
|
37
37
|
"name": "Jane Smith",
|
38
38
|
"self_url": "http://localhost/base/user/jane.smith"
|
39
39
|
}]
|
40
|
-
|
40
|
+
RESPONSE
|
41
41
|
end
|
42
42
|
|
43
43
|
stub_request(:post, 'http://localhost/base/users')
|
44
44
|
.with(body: {})
|
45
45
|
.to_return do
|
46
|
-
<<-
|
46
|
+
<<-RESPONSE.gsub(/^ {12}/, '')
|
47
47
|
HTTP/1.1 422 Unprocessable Entity
|
48
48
|
Content-Type: application/json
|
49
49
|
Transfer-Encoding: chunked
|
50
50
|
|
51
51
|
{"errors":{"name":["can't be blank"]}}
|
52
|
-
|
52
|
+
RESPONSE
|
53
53
|
end
|
54
54
|
|
55
55
|
stub_request(:post, 'http://localhost/base/users')
|
56
56
|
.with(body: {name: 'John Smith'})
|
57
57
|
.to_return do
|
58
|
-
<<-
|
58
|
+
<<-RESPONSE.gsub(/^ {12}/, '')
|
59
59
|
HTTP/1.1 201 Created
|
60
60
|
Content-Type: application/json
|
61
61
|
Location: http://localhost/base/users/john.smith
|
@@ -67,12 +67,12 @@ describe Restify do
|
|
67
67
|
"blurb_url": "http://localhost/base/users/john.smith/blurb",
|
68
68
|
"languages": ["de", "en"]
|
69
69
|
}
|
70
|
-
|
70
|
+
RESPONSE
|
71
71
|
end
|
72
72
|
|
73
73
|
stub_request(:get, 'http://localhost/base/users/john.smith')
|
74
74
|
.to_return do
|
75
|
-
<<-
|
75
|
+
<<-RESPONSE.gsub(/^ {10}/, '')
|
76
76
|
HTTP/1.1 200 OK
|
77
77
|
Content-Type: application/json
|
78
78
|
Link: <http://localhost/base/users/john.smith>; rel="self"
|
@@ -82,12 +82,12 @@ describe Restify do
|
|
82
82
|
"name": "John Smith",
|
83
83
|
"url": "http://localhost/base/users/john.smith"
|
84
84
|
}
|
85
|
-
|
85
|
+
RESPONSE
|
86
86
|
end
|
87
87
|
|
88
88
|
stub_request(:get, 'http://localhost/base/users/john.smith/blurb')
|
89
89
|
.to_return do
|
90
|
-
<<-
|
90
|
+
<<-RESPONSE.gsub(/^ {10}/, '')
|
91
91
|
HTTP/1.1 200 OK
|
92
92
|
Content-Type: application/json
|
93
93
|
Link: <http://localhost/base/users/john.smith>; rel="user"
|
@@ -97,7 +97,7 @@ describe Restify do
|
|
97
97
|
"title": "Prof. Dr. John Smith",
|
98
98
|
"image": "http://example.org/avatar.png"
|
99
99
|
}
|
100
|
-
|
100
|
+
RESPONSE
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
data/spec/spec_helper.rb
CHANGED
@@ -40,6 +40,10 @@ Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f }
|
|
40
40
|
RSpec.configure do |config|
|
41
41
|
config.order = 'random'
|
42
42
|
|
43
|
+
config.before(:suite) do
|
44
|
+
::Restify::Timeout.default_timeout = 2
|
45
|
+
end
|
46
|
+
|
43
47
|
config.before(:each) do
|
44
48
|
Ethon.logger = ::Logging.logger[Ethon] if defined?(Ethon)
|
45
49
|
|
@@ -47,9 +51,7 @@ RSpec.configure do |config|
|
|
47
51
|
::Logging.logger.root.add_appenders ::Logging.appenders.stdout
|
48
52
|
end
|
49
53
|
|
50
|
-
config.after(:
|
51
|
-
if defined?(EventMachine) && EventMachine.reactor_running?
|
52
|
-
EventMachine.stop
|
53
|
-
end
|
54
|
+
config.after(:suite) do
|
55
|
+
EventMachine.stop if defined?(EventMachine) && EventMachine.reactor_running?
|
54
56
|
end
|
55
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/restify/version.rb
|
187
187
|
- spec/restify/cache_spec.rb
|
188
188
|
- spec/restify/context_spec.rb
|
189
|
+
- spec/restify/features/head_requests_spec.rb
|
189
190
|
- spec/restify/features/request_headers_spec.rb
|
190
191
|
- spec/restify/global_spec.rb
|
191
192
|
- spec/restify/link_spec.rb
|
@@ -226,6 +227,7 @@ summary: An experimental hypermedia REST client.
|
|
226
227
|
test_files:
|
227
228
|
- spec/restify/cache_spec.rb
|
228
229
|
- spec/restify/context_spec.rb
|
230
|
+
- spec/restify/features/head_requests_spec.rb
|
229
231
|
- spec/restify/features/request_headers_spec.rb
|
230
232
|
- spec/restify/global_spec.rb
|
231
233
|
- spec/restify/link_spec.rb
|