restfulie 0.9.3 → 1.0.0.beta1
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.
- data/Gemfile +2 -0
- data/Gemfile.lock +2 -2
- data/README.textile +4 -2
- data/Rakefile +12 -13
- data/lib/restfulie/client/base.rb +9 -2
- data/lib/restfulie/client/cache/basic.rb +6 -5
- data/lib/restfulie/client/cache/http_ext.rb +10 -8
- data/lib/restfulie/client/cache/restrictions.rb +1 -6
- data/lib/restfulie/client/dsl.rb +66 -0
- data/lib/restfulie/client/entry_point.rb +34 -9
- data/lib/restfulie/client/ext/atom_ext.rb +4 -2
- data/lib/restfulie/client/ext/json_ext.rb +5 -1
- data/lib/restfulie/client/feature/base.rb +75 -0
- data/lib/restfulie/client/feature/base_request.rb +35 -0
- data/lib/restfulie/client/feature/cache.rb +16 -0
- data/lib/restfulie/client/feature/enhance_response.rb +12 -0
- data/lib/restfulie/client/feature/follow_request.rb +41 -0
- data/lib/restfulie/client/feature/history.rb +26 -0
- data/lib/restfulie/client/feature/history_request.rb +19 -0
- data/lib/restfulie/client/feature/open_search/pattern_matcher.rb +25 -0
- data/lib/restfulie/client/feature/open_search.rb +21 -0
- data/lib/restfulie/client/feature/serialize_body.rb +32 -0
- data/lib/restfulie/client/feature/setup_header.rb +22 -0
- data/lib/restfulie/client/feature/throw_error.rb +41 -0
- data/lib/restfulie/client/feature/verb.rb +119 -0
- data/lib/restfulie/client/feature.rb +5 -0
- data/lib/restfulie/client/http/response_holder.rb +26 -6
- data/lib/restfulie/client/http.rb +1 -21
- data/lib/restfulie/client/master_delegator.rb +31 -0
- data/lib/restfulie/client/mikyung/core.rb +5 -4
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +1 -1
- data/lib/restfulie/client/mikyung.rb +1 -8
- data/lib/restfulie/client.rb +3 -1
- data/lib/restfulie/common/converter/atom/base.rb +2 -0
- data/lib/restfulie/common/converter/form_url_encoded.rb +16 -0
- data/lib/restfulie/common/converter/json/base.rb +5 -2
- data/lib/restfulie/common/converter/open_search/descriptor.rb +32 -0
- data/lib/restfulie/common/converter/open_search.rb +16 -0
- data/lib/restfulie/common/converter/xml/base.rb +3 -1
- data/lib/restfulie/common/converter/xml/builder.rb +3 -2
- data/lib/restfulie/common/converter/xml/helpers.rb +4 -4
- data/lib/restfulie/common/converter/xml/link.rb +5 -0
- data/lib/restfulie/common/converter/xml/links.rb +1 -5
- data/lib/restfulie/common/converter.rb +25 -4
- data/lib/restfulie/common/core_ext/hash.rb +6 -0
- data/lib/restfulie/common/links.rb +9 -0
- data/lib/restfulie/common/representation/atom/base.rb +34 -33
- data/lib/restfulie/common/representation/atom/xml.rb +5 -10
- data/lib/restfulie/common/representation/generic.rb +0 -12
- data/lib/restfulie/common/representation/json/keys_as_methods.rb +2 -0
- data/lib/restfulie/common/representation.rb +2 -9
- data/lib/restfulie/common.rb +2 -1
- data/lib/restfulie/server/action_controller/trait/cacheable.rb +81 -0
- data/lib/restfulie/server/action_controller/trait/created.rb +17 -0
- data/lib/restfulie/server/action_controller/trait/save_prior_to_create.rb +13 -0
- data/lib/restfulie/server/action_controller/trait.rb +9 -0
- data/lib/restfulie/server/action_controller.rb +1 -5
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +1 -1
- data/lib/restfulie/server.rb +6 -0
- data/lib/restfulie/version.rb +4 -4
- data/lib/restfulie.rb +21 -3
- metadata +37 -26
- data/lib/restfulie/client/ext/xml_ext.rb +0 -4
- data/lib/restfulie/client/http/link_request_builder.rb +0 -16
- data/lib/restfulie/client/http/request_adapter.rb +0 -213
- data/lib/restfulie/client/http/request_builder.rb +0 -114
- data/lib/restfulie/client/http/request_builder_executor.rb +0 -24
- data/lib/restfulie/client/http/request_executor.rb +0 -17
- data/lib/restfulie/client/http/request_follow.rb +0 -42
- data/lib/restfulie/client/http/request_follow_executor.rb +0 -10
- data/lib/restfulie/client/http/request_history.rb +0 -71
- data/lib/restfulie/client/http/request_history_executor.rb +0 -10
- data/lib/restfulie/client/http/request_marshaller.rb +0 -129
- data/lib/restfulie/client/http/request_marshaller_executor.rb +0 -10
- data/lib/restfulie/client/http/response.rb +0 -23
- data/lib/restfulie/client/http/response_handler.rb +0 -67
- data/lib/restfulie/server/action_controller/cacheable_responder.rb +0 -77
- data/lib/restfulie/server/action_controller/created_responder.rb +0 -19
@@ -1,213 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
# Request Adapter provides a minimal interface to exchange information between server over HTTP protocol through simple adapters.
|
5
|
-
#
|
6
|
-
# All the concrete adapters follow the interface laid down in this module.
|
7
|
-
# Default connection provider is net/http
|
8
|
-
#
|
9
|
-
#==Example
|
10
|
-
#
|
11
|
-
# @re = ::Restfulie::Client::HTTP::RequestExecutor.new('http://restfulie.com') #this class includes RequestAdapter module.
|
12
|
-
# puts @re.as('application/atom+xml').get!('/posts').title #=> 'Hello World!'
|
13
|
-
#
|
14
|
-
module RequestAdapter
|
15
|
-
attr_reader :host
|
16
|
-
attr_accessor :cookies
|
17
|
-
attr_writer :default_headers
|
18
|
-
|
19
|
-
def host=(host)
|
20
|
-
if host.is_a?(::URI)
|
21
|
-
@host = host
|
22
|
-
else
|
23
|
-
@host = ::URI.parse(host)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_headers
|
28
|
-
@default_headers ||= {}
|
29
|
-
end
|
30
|
-
|
31
|
-
# GET HTTP verb without {Error}
|
32
|
-
# * <tt>path: '/posts'</tt>
|
33
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
34
|
-
def get(path, *args)
|
35
|
-
request(:get, path, *args)
|
36
|
-
end
|
37
|
-
|
38
|
-
# HEAD HTTP verb without {Error}
|
39
|
-
# * <tt>path: '/posts'</tt>
|
40
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
41
|
-
def head(path, *args)
|
42
|
-
request(:head, path, *args)
|
43
|
-
end
|
44
|
-
|
45
|
-
# POST HTTP verb without {Error}
|
46
|
-
# * <tt>path: '/posts'</tt>
|
47
|
-
# * <tt>payload: 'some text'</tt>
|
48
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
49
|
-
def post(path, payload, *args)
|
50
|
-
request(:post, path, payload, *args)
|
51
|
-
end
|
52
|
-
|
53
|
-
# PATCH HTTP verb without {Error}
|
54
|
-
# * <tt>path: '/posts'</tt>
|
55
|
-
# * <tt>payload: 'some text'</tt>
|
56
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
57
|
-
def patch(path, payload, *args)
|
58
|
-
request(:patch, path, payload, *args)
|
59
|
-
end
|
60
|
-
|
61
|
-
# PUT HTTP verb without {Error}
|
62
|
-
# * <tt>path: '/posts'</tt>
|
63
|
-
# * <tt>payload: 'some text'</tt>
|
64
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
65
|
-
def put(path, payload, *args)
|
66
|
-
request(:put, path, payload, *args)
|
67
|
-
end
|
68
|
-
|
69
|
-
# DELETE HTTP verb without {Error}
|
70
|
-
# * <tt>path: '/posts'</tt>
|
71
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
72
|
-
def delete(path, *args)
|
73
|
-
request(:delete, path, *args)
|
74
|
-
end
|
75
|
-
|
76
|
-
# GET HTTP verb {Error}
|
77
|
-
# * <tt>path: '/posts'</tt>
|
78
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
79
|
-
def get!(path, *args)
|
80
|
-
request!(:get, path, *args)
|
81
|
-
end
|
82
|
-
|
83
|
-
# HEAD HTTP verb {Error}
|
84
|
-
# * <tt>path: '/posts'</tt>
|
85
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
86
|
-
def head!(path, *args)
|
87
|
-
request!(:head, path, *args)
|
88
|
-
end
|
89
|
-
|
90
|
-
# POST HTTP verb {Error}
|
91
|
-
# * <tt>path: '/posts'</tt>
|
92
|
-
# * <tt>payload: 'some text'</tt>
|
93
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
94
|
-
def post!(path, payload, *args)
|
95
|
-
request!(:post, path, payload, *args)
|
96
|
-
end
|
97
|
-
|
98
|
-
# PATCH HTTP verb {Error}
|
99
|
-
# * <tt>path: '/posts'</tt>
|
100
|
-
# * <tt>payload: 'some text'</tt>
|
101
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
102
|
-
def patch!(path, payload, *args)
|
103
|
-
request!(:patch, path, payload, *args)
|
104
|
-
end
|
105
|
-
|
106
|
-
# PUT HTTP verb {Error}
|
107
|
-
# * <tt>path: '/posts'</tt>
|
108
|
-
# * <tt>payload: 'some text'</tt>
|
109
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
110
|
-
def put!(path, payload, *args)
|
111
|
-
request!(:put, path, payload, *args)
|
112
|
-
end
|
113
|
-
|
114
|
-
# DELETE HTTP verb {Error}
|
115
|
-
# * <tt>path: '/posts'</tt>
|
116
|
-
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
117
|
-
def delete!(path, *args)
|
118
|
-
request!(:delete, path, *args)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Executes a request against your server and return a response instance without {Error}
|
122
|
-
# * <tt>method: :get,:post,:delete,:head,:put</tt>
|
123
|
-
# * <tt>path: '/posts'</tt>
|
124
|
-
# * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
125
|
-
def request(method, path, *args)
|
126
|
-
request!(method, path, *args)
|
127
|
-
rescue Error::RESTError => se
|
128
|
-
[[@host, path], nil, se.response]
|
129
|
-
end
|
130
|
-
|
131
|
-
# Executes a request against your server and return a response instance.
|
132
|
-
# * <tt>method: :get,:post,:delete,:head,:put</tt>
|
133
|
-
# * <tt>path: '/posts'</tt>
|
134
|
-
# * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
135
|
-
def request!(method, path, *args)
|
136
|
-
headers = default_headers.merge(args.extract_options!)
|
137
|
-
unless @host.user.blank? && @host.password.blank?
|
138
|
-
headers["Authorization"] = "Basic " + ["#{@host.user}:#{@host.password}"].pack("m").delete("\r\n")
|
139
|
-
end
|
140
|
-
headers['cookie'] = @cookies if @cookies
|
141
|
-
args << headers
|
142
|
-
|
143
|
-
::Restfulie::Common::Logger.logger.info(request_to_s(method, path, *args)) if ::Restfulie::Common::Logger.logger
|
144
|
-
begin
|
145
|
-
http_request = get_connection_provider
|
146
|
-
response = Restfulie::Client.cache_provider.get([@host, path], http_request, method)
|
147
|
-
return [[@host, path], http_request, response] if response
|
148
|
-
response = ResponseHandler.handle(method, path, http_request.send(method, path, *args))
|
149
|
-
rescue Exception => e
|
150
|
-
Restfulie::Common::Logger.logger.error(e)
|
151
|
-
raise Error::ServerNotAvailableError.new(self, Response.new(method, path, 503, nil, {}), e )
|
152
|
-
end
|
153
|
-
|
154
|
-
case response.code
|
155
|
-
when 100..299
|
156
|
-
[[@host, path], http_request, response]
|
157
|
-
when 300..399
|
158
|
-
raise Error::Redirection.new(self, response)
|
159
|
-
when 400
|
160
|
-
raise Error::BadRequest.new(self, response)
|
161
|
-
when 401
|
162
|
-
raise Error::Unauthorized.new(self, response)
|
163
|
-
when 403
|
164
|
-
raise Error::Forbidden.new(self, response)
|
165
|
-
when 404
|
166
|
-
raise Error::NotFound.new(self, response)
|
167
|
-
when 405
|
168
|
-
raise Error::MethodNotAllowed.new(self, response)
|
169
|
-
when 407
|
170
|
-
raise Error::ProxyAuthenticationRequired.new(self, response)
|
171
|
-
when 409
|
172
|
-
raise Error::Conflict.new(self, response)
|
173
|
-
when 410
|
174
|
-
raise Error::Gone.new(self, response)
|
175
|
-
when 412
|
176
|
-
raise Error::PreconditionFailed.new(self, response)
|
177
|
-
when 402, 406, 408, 411, 413..499
|
178
|
-
raise Error::ClientError.new(self, response)
|
179
|
-
when 501
|
180
|
-
raise Error::NotImplemented.new(self, response)
|
181
|
-
when 500, 502..599
|
182
|
-
raise Error::ServerError.new(self, response)
|
183
|
-
else
|
184
|
-
raise Error::UnknownError.new(self, response)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
private
|
189
|
-
|
190
|
-
def get_connection_provider
|
191
|
-
@connection ||= ::Net::HTTP.new(@host.host, @host.port)
|
192
|
-
end
|
193
|
-
|
194
|
-
protected
|
195
|
-
|
196
|
-
def request_to_s(method, path, *args)
|
197
|
-
result = ["#{method.to_s.upcase} #{path}"]
|
198
|
-
|
199
|
-
arguments = args.dup
|
200
|
-
headers = arguments.extract_options!
|
201
|
-
|
202
|
-
if [:post, :put].include?(method)
|
203
|
-
body = arguments.shift
|
204
|
-
end
|
205
|
-
|
206
|
-
result << headers.collect { |key, value| "#{key}: #{value}" }.join("\n")
|
207
|
-
|
208
|
-
(result + [body ? (body.inspect + "\n") : nil]).compact.join("\n") << "\n"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
|
3
|
-
module Restfulie
|
4
|
-
module Client
|
5
|
-
module HTTP #:nodoc:
|
6
|
-
# ==== RequestBuilder
|
7
|
-
# Uses RequestAdapater to create a HTTP Request DSL
|
8
|
-
#
|
9
|
-
# ==== Example:
|
10
|
-
#
|
11
|
-
# @builder = ::Restfulie::Client::HTTP::RequestBuilderExecutor.new("http://restfulie.com") #this class includes RequestBuilder module.
|
12
|
-
# @builder.at('/posts').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200
|
13
|
-
#
|
14
|
-
module RequestBuilder
|
15
|
-
include RequestAdapter
|
16
|
-
|
17
|
-
#Set host
|
18
|
-
def at(url)
|
19
|
-
self.host = url
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
#Set Content-Type and Accept headers
|
24
|
-
def as(content_type)
|
25
|
-
headers['Content-Type'] = content_type
|
26
|
-
accepts(content_type)
|
27
|
-
end
|
28
|
-
|
29
|
-
#Set Accept headers
|
30
|
-
def accepts(content_type)
|
31
|
-
headers['Accept'] = content_type
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
# Merge internal header
|
36
|
-
#
|
37
|
-
# * <tt>headers (e.g. {'Cache-control' => 'no-cache'})</tt>
|
38
|
-
#
|
39
|
-
def with(headers)
|
40
|
-
self.headers.merge!(headers)
|
41
|
-
self
|
42
|
-
end
|
43
|
-
|
44
|
-
def headers
|
45
|
-
@headers ||= {}
|
46
|
-
end
|
47
|
-
|
48
|
-
# Path (e.g. http://restfulie.com/posts => /posts)
|
49
|
-
def path
|
50
|
-
host.path
|
51
|
-
end
|
52
|
-
|
53
|
-
def get(params = {})
|
54
|
-
request(:get, add_querystring(path, params), headers)
|
55
|
-
end
|
56
|
-
|
57
|
-
def head
|
58
|
-
request(:head, path, headers)
|
59
|
-
end
|
60
|
-
|
61
|
-
def post(payload)
|
62
|
-
request(:post, path, payload, headers)
|
63
|
-
end
|
64
|
-
|
65
|
-
def patch(payload)
|
66
|
-
request(:patch, path, payload, headers)
|
67
|
-
end
|
68
|
-
|
69
|
-
def put(payload)
|
70
|
-
request(:put, path, payload, headers)
|
71
|
-
end
|
72
|
-
|
73
|
-
def delete
|
74
|
-
request(:delete, path, headers)
|
75
|
-
end
|
76
|
-
|
77
|
-
def get!(params = {})
|
78
|
-
request!(:get, add_querystring(path, params), headers)
|
79
|
-
end
|
80
|
-
|
81
|
-
def head!
|
82
|
-
request!(:head, path, headers)
|
83
|
-
end
|
84
|
-
|
85
|
-
def post!(payload)
|
86
|
-
request!(:post, path, payload, headers)
|
87
|
-
end
|
88
|
-
|
89
|
-
def patch!(payload)
|
90
|
-
request!(:patch, path, payload, headers)
|
91
|
-
end
|
92
|
-
|
93
|
-
def put!(payload)
|
94
|
-
request!(:put, path, payload, headers)
|
95
|
-
end
|
96
|
-
|
97
|
-
def delete!
|
98
|
-
request!(:delete, path, headers)
|
99
|
-
end
|
100
|
-
|
101
|
-
protected
|
102
|
-
|
103
|
-
def add_querystring(path, params)
|
104
|
-
params = params.map { |param, value| "#{param}=#{value}"}.join("&")
|
105
|
-
params.blank? ? path : URI.escape("#{path}?#{params}")
|
106
|
-
end
|
107
|
-
|
108
|
-
def headers=(h)
|
109
|
-
@headers = h
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
#=This class includes RequestBuilder module.
|
5
|
-
class RequestBuilderExecutor < RequestExecutor
|
6
|
-
include RequestBuilder
|
7
|
-
|
8
|
-
def host=(host)
|
9
|
-
super
|
10
|
-
at(self.host.path)
|
11
|
-
end
|
12
|
-
|
13
|
-
def at(path)
|
14
|
-
@path = path
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def path
|
19
|
-
@path
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
#=This class includes RequestAdapter module.
|
5
|
-
class RequestExecutor
|
6
|
-
include RequestAdapter
|
7
|
-
|
8
|
-
# * <tt> host (e.g. 'http://restfulie.com') </tt>
|
9
|
-
# * <tt> default_headers (e.g. {'Cache-control' => 'no-cache'} ) </tt>
|
10
|
-
def initialize(host, default_headers = {})
|
11
|
-
self.host=host
|
12
|
-
self.default_headers=default_headers
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
# ==== RequestFollow follow new location of a document usually with response codes 201,301,302,303 and 307. You can also configure other codes.
|
5
|
-
#
|
6
|
-
# ==== Example:
|
7
|
-
# @executor = ::Restfulie::Client::HTTP::RequestFollowExecutor.new("http://restfulie.com") #this class includes RequestFollow module.
|
8
|
-
# @executor.at('/custom/songs').accepts('application/atom+xml').follow(201).post!("custom").code
|
9
|
-
module RequestFollow
|
10
|
-
include RequestBuilder
|
11
|
-
|
12
|
-
def follow(code = nil)
|
13
|
-
@follow ||= true # turn on follow redirection
|
14
|
-
follow_codes << code unless code.nil? or follow_codes.include?(code)
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
def request!(method, path, *args)#:nodoc:
|
19
|
-
begin
|
20
|
-
response = super
|
21
|
-
rescue Error::Redirection => e
|
22
|
-
raise e unless @follow # normal behavior for bang methods is to raise the exception
|
23
|
-
response = e.response
|
24
|
-
if follow_codes.include?(response.code)
|
25
|
-
location = response.headers['location'] || response.headers['Location']
|
26
|
-
raise Error::AutoFollowWithoutLocationError.new(self, response) unless location
|
27
|
-
self.host = location
|
28
|
-
response = super(:get, location, headers)
|
29
|
-
end
|
30
|
-
response
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
def follow_codes
|
37
|
-
@follow_codes ||= [201,301,302,303,307]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
# ==== RequestHistory
|
5
|
-
# Uses RequestBuilder and remind previous requests
|
6
|
-
#
|
7
|
-
# ==== Example:
|
8
|
-
#
|
9
|
-
# @executor = ::Restfulie::Client::HTTP::RequestHistoryExecutor.new("http://restfulie.com") #this class includes RequestHistory module.
|
10
|
-
# @executor.at('/posts').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200 #first request
|
11
|
-
# @executor.at('/blogs').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200 #second request
|
12
|
-
# @executor.request_history!(0) #doing first request
|
13
|
-
#
|
14
|
-
module RequestHistory
|
15
|
-
include RequestBuilder
|
16
|
-
|
17
|
-
def snapshots
|
18
|
-
@snapshots ||= []
|
19
|
-
end
|
20
|
-
|
21
|
-
def max_to_remind
|
22
|
-
10
|
23
|
-
end
|
24
|
-
|
25
|
-
def request!(method=nil, path=nil, *args)#:nodoc:
|
26
|
-
if method == nil || path == nil
|
27
|
-
raise 'History not selected' unless @snapshot
|
28
|
-
super( @snapshot[:method], @snapshot[:path], *@snapshot[:args] )
|
29
|
-
else
|
30
|
-
@snapshot = make_snapshot(method, path, *args)
|
31
|
-
unless snapshots.include?(@snapshot)
|
32
|
-
snapshots.shift if snapshots.size >= max_to_remind
|
33
|
-
snapshots << @snapshot
|
34
|
-
end
|
35
|
-
super
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def request(method=nil, path=nil, *args)#:nodoc:
|
40
|
-
request!(method, path, *args)
|
41
|
-
rescue Error::RESTError => se
|
42
|
-
[[@host, path], nil, se.response]
|
43
|
-
end
|
44
|
-
|
45
|
-
def history(number)
|
46
|
-
@snapshot = snapshots[number]
|
47
|
-
raise "Undefined snapshot for #{number}" unless @snapshot
|
48
|
-
self.host = @snapshot[:host]
|
49
|
-
self.cookies = @snapshot[:cookies]
|
50
|
-
self.headers = @snapshot[:headers]
|
51
|
-
self.default_headers = @snapshot[:default_headers]
|
52
|
-
at(@snapshot[:path])
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def make_snapshot(method, path, *args)
|
58
|
-
arguments = args.dup
|
59
|
-
cutom_headers = arguments.extract_options!
|
60
|
-
{ :host => self.host.dup,
|
61
|
-
:default_headers => self.default_headers.dup,
|
62
|
-
:headers => self.headers.dup,
|
63
|
-
:cookies => self.cookies,
|
64
|
-
:method => method,
|
65
|
-
:path => path,
|
66
|
-
:args => arguments << self.headers.merge(cutom_headers) }
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,129 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP
|
4
|
-
module RequestMarshaller
|
5
|
-
include RequestHistory
|
6
|
-
|
7
|
-
@@representations = {
|
8
|
-
'application/atom+xml' => ::Restfulie::Common::Converter::Atom,
|
9
|
-
'application/xml' => ::Restfulie::Common::Converter::Xml,
|
10
|
-
'text/xml' => ::Restfulie::Common::Converter::Xml,
|
11
|
-
'application/json' => ::Restfulie::Common::Converter::Json
|
12
|
-
}
|
13
|
-
|
14
|
-
def self.register_representation(media_type,representation)
|
15
|
-
@@representations[media_type] = representation
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.content_type_for(media_type)
|
19
|
-
return nil unless media_type
|
20
|
-
content_type = media_type.split(';')[0] # [/(.*?);/, 1]
|
21
|
-
@@representations[content_type]
|
22
|
-
end
|
23
|
-
|
24
|
-
def accepts(media_types)
|
25
|
-
@default_representation = @@representations[media_types]
|
26
|
-
super
|
27
|
-
end
|
28
|
-
|
29
|
-
def raw
|
30
|
-
@raw = true
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
def post(payload, options = { :recipe => nil })
|
35
|
-
request(:post, path, payload, options.merge(headers))
|
36
|
-
end
|
37
|
-
|
38
|
-
def post!(payload, options = { :recipe => nil })
|
39
|
-
request!(:post, path, payload, options.merge(headers))
|
40
|
-
end
|
41
|
-
|
42
|
-
# Executes super if its a raw request, returning the content itself.
|
43
|
-
# otherwise tries to parse the content with a mediatype handler or returns the response itself.
|
44
|
-
def request!(method, path, *args)
|
45
|
-
if has_payload?(method, path, *args)
|
46
|
-
recipe = get_recipe(*args)
|
47
|
-
|
48
|
-
payload = get_payload(method, path, *args)
|
49
|
-
rel = self.respond_to?(:rel) ? self.rel : ""
|
50
|
-
type = headers['Content-Type']
|
51
|
-
raise Restfulie::Common::Error::RestfulieError, "Missing content type related to the data to be submitted" unless type
|
52
|
-
marshaller = RequestMarshaller.content_type_for(type)
|
53
|
-
payload = marshaller.marshal(payload, { :rel => rel, :recipe => recipe }) unless payload.nil? || (payload.kind_of?(String) && payload.empty?)
|
54
|
-
args = set_marshalled_payload(method, path, payload, *args)
|
55
|
-
args = add_representation_headers(method, path, marshaller, *args)
|
56
|
-
end
|
57
|
-
|
58
|
-
if @acceptable_mediatypes
|
59
|
-
unmarshaller = RequestMarshaller.content_type_for(@acceptable_mediatypes)
|
60
|
-
args = add_representation_headers(method, path, unmarshaller, *args)
|
61
|
-
end
|
62
|
-
|
63
|
-
key, req, response = super(method, path, *args)
|
64
|
-
Restfulie::Client.cache_provider.put(key, req, response)
|
65
|
-
|
66
|
-
parse_response(response)
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
# parses the http response.
|
72
|
-
# first checks if its a 201, redirecting to the resource location.
|
73
|
-
# otherwise check if its a raw request, returning the content itself.
|
74
|
-
# finally, tries to parse the content with a mediatype handler or returns the response itself.
|
75
|
-
def parse_response(response)
|
76
|
-
if response.code == 201
|
77
|
-
request = Restfulie.at(response.headers['location'])
|
78
|
-
request.accepts(@acceptable_mediatypes) if @acceptable_mediatypes
|
79
|
-
request.get!
|
80
|
-
elsif @raw
|
81
|
-
response
|
82
|
-
elsif !response.body.empty?
|
83
|
-
representation = RequestMarshaller.content_type_for(response.headers['content-type']) || Restfulie::Common::Representation::Generic.new
|
84
|
-
representation.unmarshal(response.body).tap do |u|
|
85
|
-
u.extend(ResponseHolder)
|
86
|
-
u.response = response
|
87
|
-
end
|
88
|
-
else
|
89
|
-
response.tap do |resp|
|
90
|
-
resp.extend(ResponseHolder)
|
91
|
-
resp.response = response
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def get_recipe(*args)
|
97
|
-
headers_and_recipe = args.extract_options!
|
98
|
-
recipe = headers_and_recipe.delete(:recipe)
|
99
|
-
args << headers_and_recipe
|
100
|
-
recipe
|
101
|
-
end
|
102
|
-
|
103
|
-
def has_payload?(method, path, *args)
|
104
|
-
[:put,:post,:patch].include?(method)
|
105
|
-
end
|
106
|
-
|
107
|
-
def get_payload(method, path, *args)
|
108
|
-
args.extract_options! #remove header
|
109
|
-
args.shift #payload
|
110
|
-
end
|
111
|
-
|
112
|
-
def set_marshalled_payload(method, path, payload, *args)
|
113
|
-
headers = args.extract_options!
|
114
|
-
args.tap do |a|
|
115
|
-
a.shift #old payload
|
116
|
-
a << payload << headers
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def add_representation_headers(method, path, representation, *args)
|
121
|
-
headers = args.extract_options!
|
122
|
-
headers = headers.merge(representation.headers[method] || {})
|
123
|
-
args << headers
|
124
|
-
args
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Restfulie
|
2
|
-
module Client
|
3
|
-
module HTTP #:nodoc:
|
4
|
-
#=Response
|
5
|
-
# Default response class
|
6
|
-
class Response
|
7
|
-
attr_reader :method
|
8
|
-
attr_reader :path
|
9
|
-
attr_reader :code
|
10
|
-
attr_reader :body
|
11
|
-
attr_reader :headers
|
12
|
-
|
13
|
-
def initialize(method, path, code, body, headers)
|
14
|
-
@method = method
|
15
|
-
@path = path
|
16
|
-
@code = code
|
17
|
-
@body = body
|
18
|
-
@headers = headers
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|