httparty-cache 0.0.1 → 0.0.2
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/README.md +43 -0
- data/lib/httparty/cache/request.rb +26 -8
- data/lib/httparty/cache/response.rb +8 -7
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b5ee7949c1ff90bad003ea68a65b11de85f2aba908c3aa3b733e53976d15b33
|
4
|
+
data.tar.gz: d7f636874b72c75534ec6e060fc44c1fd3eb3191f80986b0a69bdc6c41e29279
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9af68ad0b61042517beea619be96074c5e0f8c87c99e8f1094a6d6efdc63da87a5dcb31349435d17ae61755ac34ba7a9c50709f71b4b22ed87ff93db309bca60
|
7
|
+
data.tar.gz: 59fcbe7267b2eb0670605770bdf450784d06290089cbe8c0e66cd18919283564c77b798ba7556c4c24010e6c058e0c013b4018ca723fb1ddb60862732a7ab1c5
|
data/README.md
CHANGED
@@ -33,8 +33,51 @@ class Client
|
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
+
### Caching requisites
|
37
|
+
|
38
|
+
* GET requests only.
|
39
|
+
|
40
|
+
* The server must send a `Cache-Control` header. Otherwise this gem
|
41
|
+
will always revalidate.
|
42
|
+
|
43
|
+
* A request is revalidated when:
|
44
|
+
* The server sends a `no-store` directive.
|
45
|
+
* The server sends a `no-cache` directive.
|
46
|
+
* The server sends a `max-age=0,must-revalidate` directive.
|
47
|
+
|
48
|
+
* A request is stale when its age is greater than `max-age`.
|
49
|
+
|
36
50
|
### Cache stores
|
37
51
|
|
52
|
+
Requests are stored by their URL and a cache key, and point at the
|
53
|
+
latest response.
|
54
|
+
|
55
|
+
The cache key is generated from requested URL and headers used. If the
|
56
|
+
headers change for every request or are sensitive (X-* headers used for
|
57
|
+
bespoke authentication), you can add the `cache_key: 'string'` option to
|
58
|
+
the request.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
url = 'https://example.org'
|
62
|
+
sensitive_token = 'token'
|
63
|
+
|
64
|
+
HTTParty.get(
|
65
|
+
url,
|
66
|
+
headers: { 'X-Token': sensitive_token },
|
67
|
+
cache_key: url
|
68
|
+
)
|
69
|
+
```
|
70
|
+
|
71
|
+
Otherwise you'll see many requests cached all pointing to the same
|
72
|
+
response.
|
73
|
+
|
74
|
+
`Date`, `Authorization`, `Signature` and `Cookie` headers are already
|
75
|
+
ignored.
|
76
|
+
|
77
|
+
Responses are stored by their URL and a cache key composed by its `Vary`
|
78
|
+
headers. This way if you send a request header that could change the
|
79
|
+
response, you'll get a new one.
|
80
|
+
|
38
81
|
#### Redis
|
39
82
|
|
40
83
|
If you want to use Redis as a cache store:
|
@@ -6,6 +6,7 @@ module HTTParty
|
|
6
6
|
#
|
7
7
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
|
8
8
|
module Request
|
9
|
+
SENSITIVE_HEADERS = %w[Cookie Authorization Date Signature].freeze
|
9
10
|
CACHE_REVALIDATION_HEADERS = {
|
10
11
|
'ETag' => 'If-None-Match',
|
11
12
|
'Last-Modified' => 'If-Modified-Since'
|
@@ -15,7 +16,14 @@ module HTTParty
|
|
15
16
|
#
|
16
17
|
# @return [String]
|
17
18
|
def cache_key
|
18
|
-
@cache_key ||= "request:#{uri}##{URI.encode_www_form(
|
19
|
+
@cache_key ||= "http-party-cache:request:#{uri}##{URI.encode_www_form(cache_params)}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Hash]
|
23
|
+
def cache_params
|
24
|
+
return { 'X-Cache-Key' => options[:cache_key] } if options.key? :cache_key
|
25
|
+
|
26
|
+
options[:headers].to_h.except(*SENSITIVE_HEADERS) || {}
|
19
27
|
end
|
20
28
|
|
21
29
|
def validate
|
@@ -24,14 +32,21 @@ module HTTParty
|
|
24
32
|
raise ArgumentError, 'Caching is enabled but store was not provided' if caching? && cache_store.nil?
|
25
33
|
end
|
26
34
|
|
35
|
+
# A cacheable request
|
36
|
+
#
|
37
|
+
# @return [Boolean]
|
38
|
+
def cacheable?
|
39
|
+
caching? && http_method == Net::HTTP::Get
|
40
|
+
end
|
41
|
+
|
27
42
|
# Patch HTTParty::Request#perform to provide caching for GET
|
28
43
|
# requests
|
29
44
|
#
|
30
45
|
# @return [HTTParty::Response]
|
31
46
|
def perform(&block)
|
32
|
-
return super(&block) unless
|
47
|
+
return super(&block) unless cacheable?
|
33
48
|
|
34
|
-
if
|
49
|
+
if response_cached?
|
35
50
|
handle_revalidation
|
36
51
|
else
|
37
52
|
super(&block).tap do |response|
|
@@ -46,24 +61,27 @@ module HTTParty
|
|
46
61
|
# evicted from cache or is corrupted
|
47
62
|
#
|
48
63
|
# @return [Bool]
|
49
|
-
def
|
64
|
+
def response_cached?
|
50
65
|
cache_store.key?(cache_key) &&
|
51
66
|
cache_store.key?(cache_store.get(cache_key)) &&
|
52
|
-
|
67
|
+
cached_response.is_a?(HTTParty::Response)
|
53
68
|
end
|
54
69
|
|
55
70
|
def caching?
|
56
71
|
!!options[:caching]
|
57
72
|
end
|
58
73
|
|
74
|
+
# @return [HTTParty::Response]
|
75
|
+
def cached_response
|
76
|
+
@cached_response ||= cache_store.get(cache_store.get(cache_key))
|
77
|
+
end
|
78
|
+
|
59
79
|
private
|
60
80
|
|
61
81
|
# Revalidates request
|
62
82
|
#
|
63
83
|
# @return [HTTParty::Response]
|
64
84
|
def handle_revalidation
|
65
|
-
cached_response = cache_store.get(cache_store.get(cache_key))
|
66
|
-
|
67
85
|
if cached_response.revalidate? || cached_response.stale?
|
68
86
|
self.http_method = Net::HTTP::Head
|
69
87
|
options[:cached_response] = cached_response
|
@@ -80,7 +98,7 @@ module HTTParty
|
|
80
98
|
# Remove from cache so we can perform the request, otherwise
|
81
99
|
# we produce an infinite loop
|
82
100
|
cache_store.delete(cache_key)
|
83
|
-
response = perform
|
101
|
+
@cached_response = response = perform
|
84
102
|
end
|
85
103
|
|
86
104
|
cache_store.set(response.cache_key, response)
|
@@ -6,11 +6,6 @@ module HTTParty
|
|
6
6
|
#
|
7
7
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
|
8
8
|
module Response
|
9
|
-
# Detects if response is cached
|
10
|
-
def cached?
|
11
|
-
code == 304
|
12
|
-
end
|
13
|
-
|
14
9
|
# Parses Cache-Control headers
|
15
10
|
#
|
16
11
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control}
|
@@ -54,7 +49,13 @@ module HTTParty
|
|
54
49
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#force_revalidation}
|
55
50
|
# @return [Bool]
|
56
51
|
def revalidate?
|
57
|
-
|
52
|
+
cache_control.empty? ||
|
53
|
+
cache_control[:no_store] ||
|
54
|
+
cache_control[:no_cache] ||
|
55
|
+
(
|
56
|
+
cache_control[:max_age]&.zero? &&
|
57
|
+
cache_control[:must_revalidate]
|
58
|
+
)
|
58
59
|
end
|
59
60
|
|
60
61
|
# Returns the request headers that vary responses
|
@@ -68,7 +69,7 @@ module HTTParty
|
|
68
69
|
#
|
69
70
|
# @return [String]
|
70
71
|
def cache_key
|
71
|
-
@cache_key ||= "response:#{request.uri}##{URI.encode_www_form vary}"
|
72
|
+
@cache_key ||= "httparty-cache:response:#{request.uri}##{URI.encode_www_form vary}"
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httparty-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -129,35 +129,35 @@ dependencies:
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: 0.14.0
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
132
|
+
name: jekyll
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
|
-
- - "
|
135
|
+
- - ">="
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 0
|
137
|
+
version: '0'
|
138
138
|
type: :development
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
|
-
- - "
|
142
|
+
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version: 0
|
144
|
+
version: '0'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
|
-
name:
|
146
|
+
name: redis-client
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
|
-
- - "
|
149
|
+
- - "~>"
|
150
150
|
- !ruby/object:Gem::Version
|
151
|
-
version:
|
151
|
+
version: 0.14.0
|
152
152
|
type: :development
|
153
153
|
prerelease: false
|
154
154
|
version_requirements: !ruby/object:Gem::Requirement
|
155
155
|
requirements:
|
156
|
-
- - "
|
156
|
+
- - "~>"
|
157
157
|
- !ruby/object:Gem::Version
|
158
|
-
version:
|
158
|
+
version: 0.14.0
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
|
-
name:
|
160
|
+
name: rubocop
|
161
161
|
requirement: !ruby/object:Gem::Requirement
|
162
162
|
requirements:
|
163
163
|
- - ">="
|
@@ -171,7 +171,7 @@ dependencies:
|
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0'
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
|
-
name:
|
174
|
+
name: timecop
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
176
176
|
requirements:
|
177
177
|
- - ">="
|