rack-idempotency 0.2.0 → 0.3.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/.travis.yml +5 -0
- data/README.md +5 -2
- data/lib/rack/idempotency/null_store.rb +2 -6
- data/lib/rack/idempotency/request.rb +11 -0
- data/lib/rack/idempotency/request_storage.rb +28 -0
- data/lib/rack/idempotency/response.rb +31 -0
- data/lib/rack/idempotency/version.rb +1 -1
- data/lib/rack/idempotency.rb +19 -24
- data/rack-idempotency.gemspec +2 -0
- metadata +32 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0f2c986509883647740c552f61dac9f5c7bca1b
|
4
|
+
data.tar.gz: ffd45d68ce0a2cab353ebfc69e5c72471d136bd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ba38597029bd2dcccb581da0e140aee7306ba0acf09fe17cb14a68cf613af50114fdf97d3d953e3523f4c0475f52804a26b8d458cf79b879d7690bb64749fb1
|
7
|
+
data.tar.gz: bc4879106473268af4ca39be56bcb5df5205f472cc4f1b20962d9b1ddad2f87d462ac8e54b1c7f70ef2c8f0d439c1c2af575f59cde95156016a0c55c5f479da8
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
# Rack::Idempotency
|
2
|
+
[](https://badge.fury.io/rb/rack-idempotency)
|
3
|
+
[](https://travis-ci.org/guitsaru/rack-idempotency)
|
4
|
+
[](https://codeclimate.com/github/guitsaru/rack-idempotency)
|
5
|
+
[](https://codeclimate.com/github/guitsaru/rack-idempotency/coverage)
|
2
6
|
|
3
7
|
Rack middleware ensuring at most once requests for mutating endpoints.
|
4
8
|
|
@@ -51,7 +55,7 @@ Rack::Idempotency should handle the following cases:
|
|
51
55
|
- [x] The initial connection to the server fails.
|
52
56
|
- [ ] The request fails halfway through, leaving data in limbo.
|
53
57
|
- [x] The request succeeds, but the connection to the client is lost.
|
54
|
-
|
58
|
+
|
55
59
|
The second case is much more dependent on implementation. Rack::Idempotency assumes that the request is in a transaction and
|
56
60
|
can be safely retried if it wasn't successful.
|
57
61
|
|
@@ -69,4 +73,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/guitsa
|
|
69
73
|
## License
|
70
74
|
|
71
75
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
72
|
-
|
@@ -2,13 +2,9 @@ module Rack
|
|
2
2
|
class Idempotency
|
3
3
|
# Basic version of the store. This class doesn't read or write.
|
4
4
|
class NullStore
|
5
|
-
def read(_id)
|
6
|
-
nil
|
7
|
-
end
|
5
|
+
def read(_id); end
|
8
6
|
|
9
|
-
def write(_id, _value)
|
10
|
-
nil
|
11
|
-
end
|
7
|
+
def write(_id, _value); end
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rack
|
2
|
+
class Idempotency
|
3
|
+
class RequestStorage
|
4
|
+
def initialize(store, request)
|
5
|
+
@store = store
|
6
|
+
@request = request
|
7
|
+
end
|
8
|
+
|
9
|
+
def read
|
10
|
+
stored = store.read(storage_key)
|
11
|
+
JSON.parse(stored) if stored
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(response)
|
15
|
+
store.write(storage_key, response.to_json)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :request
|
21
|
+
attr_reader :store
|
22
|
+
|
23
|
+
def storage_key
|
24
|
+
"rack:idempotency:" + request.idempotency_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rack/utils"
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Idempotency
|
5
|
+
class Response
|
6
|
+
attr_reader :status, :headers, :body
|
7
|
+
|
8
|
+
def initialize(status, headers, body)
|
9
|
+
@status = status.to_i
|
10
|
+
@headers = Rack::Utils::HeaderHash.new(headers)
|
11
|
+
@body = body
|
12
|
+
end
|
13
|
+
|
14
|
+
def success?
|
15
|
+
status.to_i >= 200 && status.to_i < 400
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
[status, headers.to_hash, body.each]
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_json
|
23
|
+
to_a.to_json
|
24
|
+
end
|
25
|
+
|
26
|
+
def idempotency_key
|
27
|
+
headers["Idempotency-Key"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/rack/idempotency.rb
CHANGED
@@ -4,6 +4,9 @@ require "rack/idempotency/version"
|
|
4
4
|
|
5
5
|
require "rack/idempotency/memory_store"
|
6
6
|
require "rack/idempotency/null_store"
|
7
|
+
require "rack/idempotency/request"
|
8
|
+
require "rack/idempotency/request_storage"
|
9
|
+
require "rack/idempotency/response"
|
7
10
|
|
8
11
|
module Rack
|
9
12
|
# Rack middleware for ensuring mutating endpoints are called at most once.
|
@@ -18,41 +21,33 @@ module Rack
|
|
18
21
|
end
|
19
22
|
|
20
23
|
def call(env)
|
21
|
-
|
22
|
-
|
23
|
-
stored = store.read(storage_key)
|
24
|
-
return JSON.parse(stored) if stored
|
24
|
+
@env = env
|
25
|
+
@request = Request.new(env.dup.freeze)
|
25
26
|
|
26
|
-
|
27
|
-
store_response(storage_key, response)
|
28
|
-
|
29
|
-
response
|
27
|
+
lookup || store_response
|
30
28
|
end
|
31
29
|
|
32
30
|
private
|
33
31
|
|
34
|
-
attr_reader :app
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
marshaled_response = response.to_json
|
39
|
-
store.write(storage_key, marshaled_response)
|
40
|
-
end
|
32
|
+
attr_reader :app
|
33
|
+
attr_reader :env
|
34
|
+
attr_reader :request
|
35
|
+
attr_reader :store
|
41
36
|
|
42
|
-
|
37
|
+
def request_store
|
38
|
+
@request_store ||= RequestStorage.new(store, request)
|
43
39
|
end
|
44
40
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
# Treat redirects as a successful response.
|
49
|
-
status.to_i >= 200 && status.to_i < 400
|
41
|
+
def lookup
|
42
|
+
request_store.read
|
50
43
|
end
|
51
44
|
|
52
|
-
def
|
53
|
-
|
45
|
+
def store_response
|
46
|
+
response = Response.new(*@app.call(env))
|
47
|
+
|
48
|
+
request_store.write(response) if response.success?
|
54
49
|
|
55
|
-
|
50
|
+
response.to_a
|
56
51
|
end
|
57
52
|
end
|
58
53
|
end
|
data/rack-idempotency.gemspec
CHANGED
@@ -25,4 +25,6 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.14"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
spec.add_development_dependency "simplecov"
|
29
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
28
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-idempotency
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Pruitt
|
@@ -66,6 +66,34 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: codeclimate-test-reporter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
description:
|
70
98
|
email:
|
71
99
|
- guitsaru@gmail.com
|
@@ -86,6 +114,9 @@ files:
|
|
86
114
|
- lib/rack/idempotency.rb
|
87
115
|
- lib/rack/idempotency/memory_store.rb
|
88
116
|
- lib/rack/idempotency/null_store.rb
|
117
|
+
- lib/rack/idempotency/request.rb
|
118
|
+
- lib/rack/idempotency/request_storage.rb
|
119
|
+
- lib/rack/idempotency/response.rb
|
89
120
|
- lib/rack/idempotency/version.rb
|
90
121
|
- rack-idempotency.gemspec
|
91
122
|
homepage: https://github.com/guitsaru/rack-idempotency
|