rest-core 2.1.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/godfat/rest-core.png?branch=master)](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.
|