rest-core 2.1.2 → 3.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/.gitignore +1 -2
- data/.travis.yml +3 -5
- data/CHANGES.md +65 -5
- data/Gemfile +10 -5
- data/NOTE.md +1 -1
- data/README.md +194 -128
- data/Rakefile +8 -34
- data/TODO.md +3 -2
- data/example/simple.rb +6 -4
- data/example/use-cases.rb +39 -122
- data/lib/rest-core.rb +14 -5
- data/lib/rest-core/builder.rb +12 -2
- data/lib/rest-core/client.rb +31 -25
- data/lib/rest-core/engine.rb +39 -0
- data/lib/rest-core/engine/http-client.rb +41 -0
- data/lib/rest-core/engine/net-http-persistent.rb +21 -0
- data/lib/rest-core/engine/rest-client.rb +13 -42
- data/lib/rest-core/event_source.rb +91 -0
- data/lib/rest-core/middleware.rb +17 -11
- data/lib/rest-core/middleware/error_detector.rb +1 -6
- data/lib/rest-core/middleware/oauth1_header.rb +1 -0
- data/lib/rest-core/middleware/oauth2_header.rb +20 -8
- data/lib/rest-core/middleware/oauth2_query.rb +1 -0
- data/lib/rest-core/middleware/timeout.rb +5 -19
- data/lib/rest-core/promise.rb +137 -0
- data/lib/rest-core/test.rb +2 -43
- data/lib/rest-core/thread_pool.rb +122 -0
- data/lib/rest-core/timer.rb +30 -0
- data/lib/rest-core/util/hmac.rb +0 -8
- data/lib/rest-core/version.rb +1 -1
- data/lib/rest-core/wrapper.rb +1 -1
- data/rest-core.gemspec +36 -25
- data/task/README.md +54 -0
- data/task/gemgem.rb +150 -156
- data/test/test_builder.rb +2 -2
- data/test/test_cache.rb +8 -8
- data/test/test_client.rb +16 -6
- data/test/test_client_oauth1.rb +1 -1
- data/test/test_event_source.rb +77 -0
- data/test/test_follow_redirect.rb +1 -1
- data/test/test_future.rb +16 -0
- data/test/test_oauth2_header.rb +28 -0
- data/test/test_promise.rb +89 -0
- data/test/test_rest-client.rb +21 -0
- data/test/test_thread_pool.rb +10 -0
- data/test/test_timeout.rb +13 -8
- metadata +61 -37
- data/example/multi.rb +0 -44
- data/lib/rest-core/engine/auto.rb +0 -25
- data/lib/rest-core/engine/em-http-request.rb +0 -90
- data/lib/rest-core/engine/future/future.rb +0 -107
- data/lib/rest-core/engine/future/future_fiber.rb +0 -32
- data/lib/rest-core/engine/future/future_thread.rb +0 -29
- data/lib/rest-core/middleware/timeout/timer_em.rb +0 -26
- data/lib/rest-core/middleware/timeout/timer_thread.rb +0 -36
- data/task/.gitignore +0 -1
- data/test/test_em-http-request.rb +0 -186
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58ed90f247d23da6267042bf108e50637e8dba98
|
4
|
+
data.tar.gz: a0d0b5f7dd766fee5426fc0faf5c5d0dd6adb229
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a45a9c11e364a08414a7e583feedbe3a289a59fba42aa8d0180e0144e91279b7a77662737c489ec466402a72db4a2833f9e674ad27954d93e325e33713f4766d
|
7
|
+
data.tar.gz: 3f3b2e09cd1131543a677e9a61cf4872c70fb272aad936eccd0f005d6490646b6589e0128ffd33f6107b644c77ef772a34f6433bd6c3d37fffe0aa1a53b72010
|
data/.gitignore
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
pkg
|
2
|
-
*.rbc
|
1
|
+
/pkg/
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,65 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## rest-core 3.0.0 -- ?
|
4
|
+
|
5
|
+
Highlights:
|
6
|
+
|
7
|
+
* Hijack for streaming responses
|
8
|
+
* EventSource for SSE (server-sent events)
|
9
|
+
* Thread pool
|
10
|
+
* Keep-alive connections from httpclient
|
11
|
+
|
12
|
+
### Incompatible changes
|
13
|
+
|
14
|
+
* Since eventmachine is buggy, and fibers without eventmachine doesn't make
|
15
|
+
too much sense, we have removed the support for eventmachine and fibers.
|
16
|
+
|
17
|
+
* We also changed the default HTTP client from rest-client to httpclient.
|
18
|
+
If you still want to use rest-client, switch it like this:
|
19
|
+
|
20
|
+
RC::Builder.default_engine = RC::RestClient
|
21
|
+
|
22
|
+
Be warned, we might remove rest-client support in the future.
|
23
|
+
|
24
|
+
* `RC::Client#options` would now return the headers instead of response body.
|
25
|
+
|
26
|
+
* Removed support for Ruby 1.8.7 without openssl installed.
|
27
|
+
|
28
|
+
* `RC::Future` is renamed to `RC::Promise`, and `RC::Future::Proxy` is
|
29
|
+
renamed to `RC::Promise::Future`.
|
30
|
+
|
31
|
+
### Enhancement
|
32
|
+
|
33
|
+
* HIJACK support, which is similar to Rack's HIJACK feature. If you're
|
34
|
+
passing `{RC::HIJACK => true}` whenever making a request, rest-core would
|
35
|
+
rather set the `RC::RESPONSE_BODY` as an empty string, and set
|
36
|
+
`RC::RESPONSE_SOCKET` as a socket for the response. This is used for
|
37
|
+
`RC::EventSource`, and you could also use this for streaming the response.
|
38
|
+
Note that this only works for default engine, httpclient.
|
39
|
+
|
40
|
+
* Introduce `RC::EventSource`. You could obtain the object via
|
41
|
+
`RC::Client#event_source`, and then setup `onopen`, `onmessage`, and
|
42
|
+
`onerror` respectively, and then call `RC::EventSource#start` to begin
|
43
|
+
making the request, and receive the SSE (sever-sent events) from the server.
|
44
|
+
This is used in `RC::Firebase` from rest-more.
|
45
|
+
|
46
|
+
* Now we have thread pool support. We could set the pool size with:
|
47
|
+
`RC::YourClient.pool_size = 10` and thread idle time with:
|
48
|
+
`RC::YourClient.pool_idle_time = 60`. By default, `pool_size` is 0
|
49
|
+
which means we don't use a thread pool. Setting it to a negative number
|
50
|
+
would mean do not spawn any threads, just make a blocking request.
|
51
|
+
`pool_idle_time` is default to 60, meaning an idle thread would be shut
|
52
|
+
down after 60 seconds without being used.
|
53
|
+
|
54
|
+
* Since we're now using httpclient by default, we should also take the
|
55
|
+
advantage of using keep-alive connections for the same host.
|
56
|
+
|
57
|
+
* Now `RC::Middleware#fail` and `RC::Middleware#log` could accept `nil` as
|
58
|
+
an input, which would then do nothing. This could much simplify the code
|
59
|
+
building middleware.
|
60
|
+
|
61
|
+
* Now we're using timers gem which should be less buggy from previous timeout.
|
62
|
+
|
3
63
|
## rest-core 2.1.2 -- 2013-05-31
|
4
64
|
|
5
65
|
### Incompatible changes
|
@@ -160,7 +220,7 @@ It's a bit outdated, but you can also checkout my blog post.
|
|
160
220
|
[rest-core 2.0 roadmap, thunk based response][post]
|
161
221
|
(p.s. now thunk is renamed to future)
|
162
222
|
|
163
|
-
[use-cases.rb]: https://github.com/
|
223
|
+
[use-cases.rb]: https://github.com/godfat/rest-core/blob/master/example/use-cases.rb
|
164
224
|
[post]: http://blogger.godfat.org/2012/06/rest-core-20-roadmap-thunk-based.html
|
165
225
|
|
166
226
|
### Incompatible changes
|
@@ -263,8 +323,8 @@ This is a very significant release. The most important change is now we
|
|
263
323
|
support asynchronous requests, by either passing a callback block or using
|
264
324
|
fibers in Ruby 1.9 to make the whole program still look synchronous.
|
265
325
|
|
266
|
-
Please read [README.md](https://github.com/
|
267
|
-
or [example](https://github.com/
|
326
|
+
Please read [README.md](https://github.com/godfat/rest-core/blob/master/README.md)
|
327
|
+
or [example](https://github.com/godfat/rest-core/tree/master/example)
|
268
328
|
for more detail.
|
269
329
|
|
270
330
|
* [`Client`] Client#inspect is fixed for clients which do not have any
|
@@ -472,7 +532,7 @@ others are moved to [rest-more][]. Since bundler didn't like cyclic
|
|
472
532
|
dependency, so rest-core is not depending on rest-more. Please install
|
473
533
|
_rest-more_ if you want to use them.
|
474
534
|
|
475
|
-
[rest-more]: https://github.com/
|
535
|
+
[rest-more]: https://github.com/godfat/rest-more
|
476
536
|
|
477
537
|
## rest-core 0.4.0 -- 2011-09-26
|
478
538
|
|
@@ -563,7 +623,7 @@ _rest-more_ if you want to use them.
|
|
563
623
|
twitter:
|
564
624
|
consumer_key: abc
|
565
625
|
|
566
|
-
[rest-graph]: https://github.com/
|
626
|
+
[rest-graph]: https://github.com/godfat/rest-graph
|
567
627
|
|
568
628
|
## rest-core 0.2.3 -- 2011-08-27
|
569
629
|
|
data/Gemfile
CHANGED
@@ -4,11 +4,10 @@ source 'https://rubygems.org/'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
gem 'rest-client'
|
7
|
-
gem 'em-http-request'
|
8
7
|
|
9
8
|
gem 'rake'
|
10
9
|
gem 'bacon'
|
11
|
-
gem '
|
10
|
+
gem 'muack'
|
12
11
|
gem 'webmock'
|
13
12
|
|
14
13
|
gem 'json'
|
@@ -16,12 +15,18 @@ gem 'json_pure'
|
|
16
15
|
gem 'multi_json'
|
17
16
|
|
18
17
|
gem 'rack'
|
19
|
-
gem 'ruby-hmac'
|
20
18
|
|
21
|
-
platforms
|
19
|
+
platforms :ruby do
|
22
20
|
gem 'yajl-ruby'
|
23
21
|
end
|
24
22
|
|
25
|
-
platforms
|
23
|
+
platforms :rbx do
|
24
|
+
gem 'rubysl-weakref' # used in rest-core
|
25
|
+
gem 'rubysl-singleton' # used in rake
|
26
|
+
gem 'rubysl-rexml' # used in crack used in webmock
|
27
|
+
gem 'rubysl-bigdecimal' # used in crack used in webmock
|
28
|
+
end
|
29
|
+
|
30
|
+
platforms :jruby do
|
26
31
|
gem 'jruby-openssl'
|
27
32
|
end
|
data/NOTE.md
CHANGED
@@ -43,6 +43,6 @@ and use that along with pre-built ones to compose a very customized client.
|
|
43
43
|
|
44
44
|
We present you rest-core.
|
45
45
|
|
46
|
-
[rest-core]: https://github.com/
|
46
|
+
[rest-core]: https://github.com/godfat/rest-core
|
47
47
|
[Rack]: https://github.com/rack/rack
|
48
48
|
[Faraday]: https://github.com/technoweenie/faraday
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rest-core [](http://travis-ci.org/godfat/rest-core)
|
2
2
|
|
3
|
-
by
|
3
|
+
by Lin Jen-Shin ([godfat](http://godfat.org))
|
4
4
|
|
5
5
|
Lin Jen-Shin ([godfat][]) had given a talk about rest-core on
|
6
6
|
[RubyConf Taiwan 2011][talk]. The slide is in English, but the
|
@@ -11,9 +11,9 @@ talk is in Mandarin.
|
|
11
11
|
|
12
12
|
## LINKS:
|
13
13
|
|
14
|
-
* [github](https://github.com/
|
14
|
+
* [github](https://github.com/godfat/rest-core)
|
15
15
|
* [rubygems](https://rubygems.org/gems/rest-core)
|
16
|
-
* [rdoc](http://rdoc.info/projects/
|
16
|
+
* [rdoc](http://rdoc.info/projects/godfat/rest-core)
|
17
17
|
* [mailing list](http://groups.google.com/group/rest-core/topics)
|
18
18
|
|
19
19
|
## DESCRIPTION:
|
@@ -27,28 +27,36 @@ that allows you to build a REST client for any REST API. Or in the case of
|
|
27
27
|
common APIs such as Facebook, Github, and Twitter, you can simply use the
|
28
28
|
dedicated clients provided by [rest-more][].
|
29
29
|
|
30
|
-
[rest-more]: https://github.com/
|
30
|
+
[rest-more]: https://github.com/godfat/rest-more
|
31
31
|
|
32
32
|
## FEATURES:
|
33
33
|
|
34
34
|
* Modular interface for REST clients similar to WSGI/Rack for servers.
|
35
35
|
* Concurrent requests with synchronous or asynchronous interfaces with
|
36
|
-
|
36
|
+
threads.
|
37
|
+
|
38
|
+
## WHY?
|
39
|
+
|
40
|
+
Build your own API clients for less dependencies, less codes,
|
41
|
+
less memory, less conflicts, and run faster.
|
37
42
|
|
38
43
|
## REQUIREMENTS:
|
39
44
|
|
40
45
|
### Mandatory:
|
41
46
|
|
42
|
-
* MRI (official CRuby)
|
43
|
-
* gem
|
47
|
+
* Tested with MRI (official CRuby), Rubinius and JRuby.
|
48
|
+
* gem [httpclient][]
|
49
|
+
* gem [mime-types][]
|
50
|
+
* gem [timers][]
|
51
|
+
|
52
|
+
[httpclient]: https://github.com/nahi/httpclient
|
53
|
+
[mime-types]: https://github.com/halostatue/mime-types
|
54
|
+
[timers]: https://github.com/celluloid/timers
|
44
55
|
|
45
56
|
### Optional:
|
46
57
|
|
47
|
-
* gem [em-http-request][] (if using eventmachine)
|
48
58
|
* gem json or yajl-ruby, or multi_json (if `JsonResponse` or
|
49
|
-
`JsonRequest`
|
50
|
-
|
51
|
-
[em-http-request]: https://github.com/igrigorik/em-http-request
|
59
|
+
`JsonRequest` middleware is used)
|
52
60
|
|
53
61
|
## INSTALLATION:
|
54
62
|
|
@@ -59,14 +67,14 @@ gem install rest-core
|
|
59
67
|
Or if you want development version, put this in Gemfile:
|
60
68
|
|
61
69
|
``` ruby
|
62
|
-
gem 'rest-core', :git => 'git://github.com/
|
70
|
+
gem 'rest-core', :git => 'git://github.com/godfat/rest-core.git',
|
63
71
|
:submodules => true
|
64
72
|
```
|
65
73
|
|
66
74
|
If you just want to use Facebook or Twitter clients, please take a look at
|
67
75
|
[rest-more][] which has a lot of clients built with rest-core.
|
68
76
|
|
69
|
-
[rest-more]: http://github.com/
|
77
|
+
[rest-more]: http://github.com/godfat/rest-more
|
70
78
|
|
71
79
|
## Build Your Own Clients:
|
72
80
|
|
@@ -90,12 +98,12 @@ configuration, e.g. different cache time or timeout time):
|
|
90
98
|
|
91
99
|
``` ruby
|
92
100
|
client = YourClient.new(:cache => {})
|
93
|
-
client.get('
|
94
|
-
client.get('
|
101
|
+
client.get('godfat') # cache miss
|
102
|
+
client.get('godfat') # cache hit
|
95
103
|
|
96
104
|
client.site = 'http://github.com/api/v2/json/user/show/'
|
97
|
-
client.get('
|
98
|
-
client.get('
|
105
|
+
client.get('godfat') # cache miss
|
106
|
+
client.get('godfat') # cache hit
|
99
107
|
```
|
100
108
|
|
101
109
|
### Concurrent Requests with Futures:
|
@@ -104,7 +112,7 @@ You can also make concurrent requests easily:
|
|
104
112
|
(see "Advanced Concurrent HTTP Requests -- Embrace the Future" for detail)
|
105
113
|
|
106
114
|
``` ruby
|
107
|
-
a = [client.get('
|
115
|
+
a = [client.get('godfat'), client.get('cardinalblue')]
|
108
116
|
puts "It's not blocking... but doing concurrent requests underneath"
|
109
117
|
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
110
118
|
puts "DONE"
|
@@ -165,7 +173,7 @@ should work.
|
|
165
173
|
On the other hand, callback mode also available:
|
166
174
|
|
167
175
|
``` ruby
|
168
|
-
client.get('
|
176
|
+
client.get('godfat'){ |v| p v }
|
169
177
|
puts "It's not blocking... but doing concurrent requests underneath"
|
170
178
|
client.wait # we block here to wait for the request done
|
171
179
|
puts "DONE"
|
@@ -191,6 +199,108 @@ client.wait # we block here to wait for the request done
|
|
191
199
|
puts "DONE"
|
192
200
|
```
|
193
201
|
|
202
|
+
### Thread Pool / Connection Pool
|
203
|
+
|
204
|
+
Underneath, rest-core would spawn a thread for each request, freeing you
|
205
|
+
from blocking. However, occasionally we would not want this behaviour,
|
206
|
+
giving that we might have limited resource and cannot maximize performance.
|
207
|
+
|
208
|
+
For example, maybe we could not afford so many threads running concurrently,
|
209
|
+
or the target server cannot accept so many concurrent connections. In those
|
210
|
+
cases, we would want to have limited concurrent threads or connections.
|
211
|
+
|
212
|
+
``` ruby
|
213
|
+
YourClient.pool_size = 10
|
214
|
+
YourClient.pool_idle_time = 60
|
215
|
+
```
|
216
|
+
|
217
|
+
This could set the thread pool size to 10, having a maximum of 10 threads
|
218
|
+
running together, growing from requests. Each threads idled more than 60
|
219
|
+
seconds would be shut down automatically.
|
220
|
+
|
221
|
+
Note that `pool_size` should at least be larger than 4, or it might be
|
222
|
+
very likely to have _deadlock_ if you're using nested callbacks and having
|
223
|
+
a large number of concurrent calls.
|
224
|
+
|
225
|
+
Also, setting `pool_size` to `-1` would mean we want to make blocking
|
226
|
+
requests, without spawning any threads. This might be useful for debugging.
|
227
|
+
|
228
|
+
### Persistent connections (keep-alive connections)
|
229
|
+
|
230
|
+
Since we're using [httpclient][] by default now, we would reuse connections,
|
231
|
+
making it much faster for hitting the same host repeatedly.
|
232
|
+
|
233
|
+
### Streaming Requests
|
234
|
+
|
235
|
+
Suppose we want to POST a file, instead of trying to read all the contents
|
236
|
+
in memory and send them, we could stream it from the file system directly.
|
237
|
+
|
238
|
+
``` ruby
|
239
|
+
client.post('path', File.open('README.md'))
|
240
|
+
```
|
241
|
+
|
242
|
+
Basically, payloads could be any IO object. Check out
|
243
|
+
[RC::Payload](lib/rest-core/util/payload.rb) for more information.
|
244
|
+
|
245
|
+
### Streaming Responses
|
246
|
+
|
247
|
+
This one is much harder then streaming requests, since all built-in
|
248
|
+
middleware actually assume the responses should be blocking and buffered.
|
249
|
+
Say, some JSON parser could not really parse from streams.
|
250
|
+
|
251
|
+
We solve this issue similarly to the way Rack solves it. That is, we hijack
|
252
|
+
the socket. This would be how we're doing:
|
253
|
+
|
254
|
+
``` ruby
|
255
|
+
sock = client.get('path', {}, RC::HIJACK => true)
|
256
|
+
p sock.read(10)
|
257
|
+
p sock.read(10)
|
258
|
+
p sock.read(10)
|
259
|
+
```
|
260
|
+
|
261
|
+
Of course, if we don't want to block in order to get the socket, we could
|
262
|
+
always use the callback form:
|
263
|
+
|
264
|
+
``` ruby
|
265
|
+
client.get('path', {}, RC::HIJACK => true) do |sock|
|
266
|
+
p sock.read(10)
|
267
|
+
p sock.read(10)
|
268
|
+
p sock.read(10)
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
272
|
+
Note that since the socket would be put inside `RC::RESPONSE_SOCKET`
|
273
|
+
instead of `RC::RESPONSE_BODY`, not all middleware would handle the socket.
|
274
|
+
In the case of hijacking, `RC::RESPONSE_BODY` would always be mapped to an
|
275
|
+
empty string, as it does not make sense to store the response in this case.
|
276
|
+
|
277
|
+
### SSE (Server-Sent Events)
|
278
|
+
|
279
|
+
Not only JavaScript could receive server-sent events, any languages could.
|
280
|
+
Doing so would establish a keep-alive connection to the server, and receive
|
281
|
+
data periodically. We'll take Firebase as an example:
|
282
|
+
|
283
|
+
``` ruby
|
284
|
+
es = RC::Universal.new.event_source(
|
285
|
+
'https://SampleChat.firebaseIO-demo.com/users/tom/.json')
|
286
|
+
|
287
|
+
es.onopen{ |sock| p "Socket: #{sock}" }
|
288
|
+
es.onmessage{ |event| p "Event: #{event}" }
|
289
|
+
es.onerror{ |error| p "Error: #{error}" }
|
290
|
+
|
291
|
+
es.start # Start making the request
|
292
|
+
sleep(5) # Sleep awhile to see anything is happening
|
293
|
+
es.close # Close the connection when we're done
|
294
|
+
```
|
295
|
+
|
296
|
+
Those callbacks would be called in a separate background thread,
|
297
|
+
so we don't have to worry about blocking it. If we want to wait for
|
298
|
+
the connection to be closed, we could call `wait`:
|
299
|
+
|
300
|
+
``` ruby
|
301
|
+
es.wait # This would block until the connection is closed
|
302
|
+
```
|
303
|
+
|
194
304
|
### More Control with `request_full`:
|
195
305
|
|
196
306
|
You can also use `request_full` to retrieve everything including response
|
@@ -202,17 +312,15 @@ including the path.
|
|
202
312
|
``` ruby
|
203
313
|
client.request_full({})[RC::RESPONSE_BODY] # {"message"=>"Not Found"}
|
204
314
|
# This would print something like this:
|
205
|
-
# RestCore:
|
206
|
-
# RestCore: Future picked: RestCore::Future::FutureThread
|
207
|
-
# RestCore: spent 1.135713 Requested GET https://api.github.com/users//
|
315
|
+
# RestCore: spent 1.135713 Requested GET https://api.github.com/users/
|
208
316
|
|
209
|
-
client.request_full(RC::REQUEST_PATH => '
|
210
|
-
client.request_full(RC::REQUEST_PATH => '
|
317
|
+
client.request_full(RC::REQUEST_PATH => 'godfat')[RC::RESPONSE_STATUS]
|
318
|
+
client.request_full(RC::REQUEST_PATH => 'godfat')[RC::RESPONSE_HEADERS]
|
211
319
|
# Headers are normalized with all upper cases and
|
212
320
|
# dashes are replaced by underscores.
|
213
321
|
|
214
322
|
# To make POST (or any other request methods) request:
|
215
|
-
client.request_full(RC::REQUEST_PATH => '
|
323
|
+
client.request_full(RC::REQUEST_PATH => 'godfat',
|
216
324
|
RC::REQUEST_METHOD => :post)[RC::RESPONSE_STATUS] # 404
|
217
325
|
```
|
218
326
|
|
@@ -222,15 +330,15 @@ Runnable example is at: [example/simple.rb][]. Please see [rest-more][]
|
|
222
330
|
for more complex examples to build clients, and [slides][] from
|
223
331
|
[rubyconf.tw/2011][rubyconf.tw] for concepts.
|
224
332
|
|
225
|
-
[example/simple.rb]:
|
226
|
-
[rest-more]: https://github.com/
|
333
|
+
[example/simple.rb]: example/simple.rb
|
334
|
+
[rest-more]: https://github.com/godfat/rest-more
|
227
335
|
[slides]: http://www.godfat.org/slide/2011-08-27-rest-core.html
|
228
336
|
[rubyconf.tw]: http://rubyconf.tw/2011/#6
|
229
337
|
|
230
338
|
## Playing Around:
|
231
339
|
|
232
340
|
You can also play around with `RC::Universal` client, which has installed
|
233
|
-
_all_ reasonable
|
341
|
+
_all_ reasonable middleware built-in rest-core. So the above example could
|
234
342
|
also be achieved by:
|
235
343
|
|
236
344
|
``` ruby
|
@@ -238,7 +346,7 @@ require 'rest-core'
|
|
238
346
|
client = RC::Universal.new(:site => 'https://api.github.com/users/',
|
239
347
|
:json_response => true,
|
240
348
|
:log_method => method(:puts))
|
241
|
-
client.get('
|
349
|
+
client.get('godfat')
|
242
350
|
```
|
243
351
|
|
244
352
|
`RC::Universal` is defined as:
|
@@ -276,7 +384,7 @@ rib rest-core
|
|
276
384
|
And you will be entering a rib shell, which `self` is an instance of
|
277
385
|
`RC::Universal` you can play:
|
278
386
|
|
279
|
-
rest-core>> get 'https://api.github.com/users/
|
387
|
+
rest-core>> get 'https://api.github.com/users/godfat'
|
280
388
|
|
281
389
|
will print out the response from Github. You can also do this to make
|
282
390
|
calling Github easier:
|
@@ -286,36 +394,56 @@ calling Github easier:
|
|
286
394
|
|
287
395
|
Then it would do exactly like the original example:
|
288
396
|
|
289
|
-
rest-core>> get '
|
397
|
+
rest-core>> get 'godfat' # you get a nice parsed hash
|
290
398
|
|
291
399
|
This is mostly for fun and experimenting, so it's only included in
|
292
400
|
[rest-more][] and [rib][]. Please make sure you have both of them
|
293
401
|
installed before trying this.
|
294
402
|
|
295
403
|
[rib]: https://github.com/godfat/rib
|
296
|
-
[rest-more]: https://github.com/
|
404
|
+
[rest-more]: https://github.com/godfat/rest-more
|
297
405
|
|
298
406
|
## List of built-in Middleware:
|
299
407
|
|
300
|
-
*
|
301
|
-
*
|
302
|
-
*
|
303
|
-
*
|
304
|
-
*
|
305
|
-
*
|
306
|
-
*
|
307
|
-
*
|
308
|
-
*
|
309
|
-
*
|
310
|
-
*
|
311
|
-
*
|
312
|
-
*
|
313
|
-
*
|
314
|
-
*
|
315
|
-
*
|
316
|
-
*
|
317
|
-
*
|
318
|
-
*
|
408
|
+
* [RC::AuthBasic][]
|
409
|
+
* [RC::Bypass][]
|
410
|
+
* [RC::Cache][]
|
411
|
+
* [RC::CommonLogger][]
|
412
|
+
* [RC::DefaultHeaders][]
|
413
|
+
* [RC::DefaultPayload][]
|
414
|
+
* [RC::DefaultQuery][]
|
415
|
+
* [RC::DefaultSite][]
|
416
|
+
* [RC::Defaults][]
|
417
|
+
* [RC::ErrorDetector][]
|
418
|
+
* [RC::ErrorDetectorHttp][]
|
419
|
+
* [RC::ErrorHandler][]
|
420
|
+
* [RC::FollowRedirect][]
|
421
|
+
* [RC::JsonRequest][]
|
422
|
+
* [RC::JsonResponse][]
|
423
|
+
* [RC::Oauth1Header][]
|
424
|
+
* [RC::Oauth2Header][]
|
425
|
+
* [RC::Oauth2Query][]
|
426
|
+
* [RC::Timeout][]
|
427
|
+
|
428
|
+
[RC::AuthBasic]: lib/rest-core/middleware/auth_basic.rb
|
429
|
+
[RC::Bypass]: lib/rest-core/middleware/bypass.rb
|
430
|
+
[RC::Cache]: lib/rest-core/middleware/cache.rb
|
431
|
+
[RC::CommonLogger]: lib/rest-core/middleware/common_logger.rb
|
432
|
+
[RC::DefaultHeaders]: lib/rest-core/middleware/default_headers.rb
|
433
|
+
[RC::DefaultPayload]: lib/rest-core/middleware/default_payload.rb
|
434
|
+
[RC::DefaultQuery]: lib/rest-core/middleware/default_query.rb
|
435
|
+
[RC::DefaultSite]: lib/rest-core/middleware/default_site.rb
|
436
|
+
[RC::Defaults]: lib/rest-core/middleware/defaults.rb
|
437
|
+
[RC::ErrorDetector]: lib/rest-core/middleware/error_detector.rb
|
438
|
+
[RC::ErrorDetectorHttp]: lib/rest-core/middleware/error_detector_http.rb
|
439
|
+
[RC::ErrorHandler]: lib/rest-core/middleware/error_handler.rb
|
440
|
+
[RC::FollowRedirect]: lib/rest-core/middleware/follow_redirect.rb
|
441
|
+
[RC::JsonRequest]: lib/rest-core/middleware/json_request.rb
|
442
|
+
[RC::JsonResponse]: lib/rest-core/middleware/json_response.rb
|
443
|
+
[RC::Oauth1Header]: lib/rest-core/middleware/oauth1_header.rb
|
444
|
+
[RC::Oauth2Header]: lib/rest-core/middleware/oauth2_header.rb
|
445
|
+
[RC::Oauth2Query]: lib/rest-core/middleware/oauth2_query.rb
|
446
|
+
[RC::Timeout]: lib/rest-core/middleware/timeout.rb
|
319
447
|
|
320
448
|
## Build Your Own Middleware:
|
321
449
|
|
@@ -425,8 +553,8 @@ YourClient = RC::Builder.client do
|
|
425
553
|
end
|
426
554
|
|
427
555
|
client = YourClient.new
|
428
|
-
puts "
|
429
|
-
a = [client.get('
|
556
|
+
puts "httpclient with threads doing concurrent requests"
|
557
|
+
a = [client.get('godfat'), client.get('cardinalblue')]
|
430
558
|
puts "It's not blocking... but doing concurrent requests underneath"
|
431
559
|
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
432
560
|
puts "DONE"
|
@@ -443,11 +571,11 @@ YourClient = RC::Builder.client do
|
|
443
571
|
end
|
444
572
|
|
445
573
|
client = YourClient.new
|
446
|
-
puts "
|
447
|
-
client.get('
|
574
|
+
puts "httpclient with threads doing concurrent requests"
|
575
|
+
client.get('godfat'){ |v|
|
448
576
|
p v['name']
|
449
577
|
}.
|
450
|
-
get('
|
578
|
+
get('cardinalblue'){ |v|
|
451
579
|
p v['name']
|
452
580
|
}
|
453
581
|
puts "It's not blocking... but doing concurrent requests underneath"
|
@@ -459,85 +587,21 @@ You can pick whatever works for you.
|
|
459
587
|
|
460
588
|
[future]: http://en.wikipedia.org/wiki/Futures_and_promises
|
461
589
|
|
462
|
-
|
463
|
-
|
464
|
-
In the above example, we're using rest-client with threads, which works
|
465
|
-
for most of cases. But you might also want to use em-http-request with
|
466
|
-
EventMachine, which is using a faster HTTP parser. In theory, it should
|
467
|
-
be much more efficient than rest-client and threads.
|
468
|
-
|
469
|
-
To pick em-http-request, you must run the requests inside the EventMachine's
|
470
|
-
event loop, and also wrap your request with either a thread or a fiber,
|
471
|
-
because we can't block the event loop and ask em-http-request to finish
|
472
|
-
its job making requests.
|
473
|
-
|
474
|
-
Here's an example of using em-http-request with threads:
|
475
|
-
|
476
|
-
``` ruby
|
477
|
-
require 'em-http-request'
|
478
|
-
require 'rest-core'
|
479
|
-
YourClient = RC::Builder.client do
|
480
|
-
use RC::DefaultSite , 'https://api.github.com/users/'
|
481
|
-
use RC::JsonResponse, true
|
482
|
-
use RC::CommonLogger, method(:puts)
|
483
|
-
end
|
484
|
-
|
485
|
-
client = YourClient.new
|
486
|
-
puts "eventmachine with threads doing concurrent requests"
|
487
|
-
EM.run{
|
488
|
-
Thread.new{
|
489
|
-
a = [client.get('cardinalblue'), client.get('godfat')]
|
490
|
-
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
491
|
-
puts "DONE"
|
492
|
-
EM.stop
|
493
|
-
}
|
494
|
-
puts "It's not blocking... but doing concurrent requests underneath"
|
495
|
-
}
|
496
|
-
```
|
497
|
-
|
498
|
-
And here's an example of using em-http-request with fibers:
|
499
|
-
|
500
|
-
``` ruby
|
501
|
-
require 'fiber' # remember to require fiber first,
|
502
|
-
require 'em-http-request' # or rest-core won't pick fibers
|
503
|
-
require 'rest-core'
|
504
|
-
YourClient = RC::Builder.client do
|
505
|
-
use RC::DefaultSite , 'https://api.github.com/users/'
|
506
|
-
use RC::JsonResponse, true
|
507
|
-
use RC::CommonLogger, method(:puts)
|
508
|
-
end
|
509
|
-
|
510
|
-
client = YourClient.new
|
511
|
-
puts "eventmachine with fibers doing concurrent requests"
|
512
|
-
EM.run{
|
513
|
-
Fiber.new{
|
514
|
-
a = [client.get('cardinalblue'), client.get('godfat')]
|
515
|
-
p a.map{ |r| r['name'] } # here we want the values, so it blocks here
|
516
|
-
puts "DONE"
|
517
|
-
EM.stop
|
518
|
-
}
|
519
|
-
puts "It's not blocking... but doing concurrent requests underneath"
|
520
|
-
}
|
521
|
-
```
|
522
|
-
|
523
|
-
As you can see, both of them are quite similar to each other, because the
|
524
|
-
idea behind the scene is the same. If you don't know what concurrency model
|
525
|
-
to pick, start with rest-client since it's the easiest one to setup.
|
526
|
-
|
527
|
-
A full runnable example is at: [example/multi.rb][]. If you want to know
|
590
|
+
A full runnable example is at: [example/simple.rb][]. If you want to know
|
528
591
|
all the possible use cases, you can also see: [example/use-cases.rb][]. It's
|
529
592
|
also served as a test for each possible combinations, so it's quite complex
|
530
593
|
and complete.
|
531
594
|
|
532
|
-
[example/
|
533
|
-
|
534
|
-
[example/use-cases.rb]: https://github.com/cardinalblue/rest-core/blob/master/example/use-cases.rb
|
595
|
+
[example/simple.rb]: example/simple.rb
|
596
|
+
[example/use-cases.rb]: example/use-cases.rb
|
535
597
|
|
536
598
|
## rest-core users:
|
537
599
|
|
538
|
-
* [
|
600
|
+
* [rest-more][]
|
601
|
+
* [rest-more-yahoo_buy](https://github.com/GoodLife/rest-more-yahoo_buy)
|
539
602
|
* [s2sync](https://github.com/brucehsu/s2sync)
|
540
603
|
* [s2sync_web](https://github.com/brucehsu/s2sync_web)
|
604
|
+
* [topcoder](https://github.com/miaout17/topcoder)
|
541
605
|
|
542
606
|
## Powered sites:
|
543
607
|
|
@@ -545,7 +609,7 @@ and complete.
|
|
545
609
|
|
546
610
|
## CHANGES:
|
547
611
|
|
548
|
-
* [CHANGES](
|
612
|
+
* [CHANGES](CHANGES.md)
|
549
613
|
|
550
614
|
## CONTRIBUTORS:
|
551
615
|
|
@@ -557,7 +621,9 @@ and complete.
|
|
557
621
|
* Florent Vaucelle (@florent)
|
558
622
|
* Jaime Cham (@jcham)
|
559
623
|
* John Fan (@johnfan)
|
624
|
+
* khoa nguyen (@khoan)
|
560
625
|
* Lin Jen-Shin (@godfat)
|
626
|
+
* lulalala (@lulalala)
|
561
627
|
* Mariusz Pruszynski (@snicky)
|
562
628
|
* Mr. Big Cat (@miaout17)
|
563
629
|
* Nicolas Fouché (@nfo)
|
@@ -567,7 +633,7 @@ and complete.
|
|
567
633
|
|
568
634
|
Apache License 2.0
|
569
635
|
|
570
|
-
Copyright (c) 2011-
|
636
|
+
Copyright (c) 2011-2014, Lin Jen-Shin (godfat)
|
571
637
|
|
572
638
|
Licensed under the Apache License, Version 2.0 (the "License");
|
573
639
|
you may not use this file except in compliance with the License.
|