From 2d5542f25668630bbec29908f6d500bfa82d8b63 Mon Sep 17 00:00:00 2001 From: Dmytro Zakharov Date: Mon, 22 Jan 2018 18:54:39 +0100 Subject: [PATCH] update readme --- README.md | 116 ++++++++++++++++++++++++++++++++++--- idempotent-request.gemspec | 5 +- 2 files changed, 109 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b54c1e9..ede9f1d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -# Idempotent::Request +# Idempotent Request -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/idempotent/request`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem +Rack middleware ensuring at most once requests for mutating endpoints. ## Installation @@ -20,15 +18,115 @@ Or install it yourself as: $ gem install idempotent-request -## Usage +## How it works -TODO: Write usage instructions here +1. Front-end generates a unique `key` then a user goes to a specific route (for example, transfer page). +2. When user clicks "Submit" button, the `key` is sent in the header `idempotency-key` and back-end stores server response into redis. +3. All the consecutive requests with the `key` won't be executer by the server and the result of previous response (2) will be fetched from redis. +4. Once the user leaves or refreshes the page, front-end should re-generate the key. -## Development +## Configuration +```ruby +# application.rb +config.middleware.use IdempotentRequest::Middleware, + storage: IdempotentRequest::RedisStorage.new(::Redis.current, expire_time: 1.day), + policy: YOUR_CLASS +``` -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +To define a policy, whether a request should be idempotent, you have to provider a class with the following interface: -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). +```ruby +class Policy + attr_reader :request + + def initialize(request) + @request = request + end + + def should? + # request is Rack::Request class + end +end +``` + +### Example of integration for rails + + +```ruby +# application.rb +config.middleware.use IdempotentRequest::Middleware, + storage: IdempotentRequest::RedisStorage.new(::Redis.current, expire_time: 1.day), + policy: IdempotentRequest::Policy + +config.idempotent_routes = [ + { controller: :'v1/transfers', action: :create }, +] +``` + +```ruby +# lib/idempotent-request/policy.rb +module IdempotentRequest + class Policy + attr_reader :request + + def initialize(request) + @request = request + end + + def should? + route = Rails.application.routes.recognize_path(request.path, method: request.request_method) + Rails.application.config.idempotent_routes.any? do |idempotent_route| + idempotent_route[:controller] == route[:controller].to_sym && + idempotent_route[:action] == route[:action].to_sym + end + end + end +end +``` + +## Custom options + +```ruby +# application.rb +config.middleware.use IdempotentRequest::Middleware, + header_key: 'X-Qonto-Idempotency-Key', # by default Idempotency-key + policy: IdempotentRequest::Policy, + callback: IdempotentRequest::RailsCallback, + storage: IdempotentRequest::RedisStorage.new(::Redis.current, expire_time: 1.day, namespace: 'idempotency_keys') +``` + +### Policy + +Custom class to decide whether the request should be idempotent. + +See *Example of integration for rails* + +### Storage + +Where the response will be stored. Can be any class that implements the following interface: + +```ruby +def read(key) + # read from a storage +end + +def write(key, payload) + # write to a storage +end +``` + +### Callback + +Get notified when the client sends a request with the same idempotency key: + +```ruby +class RailsCallback < Callback + def detected(key:) + # `request` is also available + Rails.logger.warn "IdempotentRequest request detected, key: #{key}" + end +end +``` ## Contributing diff --git a/idempotent-request.gemspec b/idempotent-request.gemspec index 98eda8c..e289f4c 100644 --- a/idempotent-request.gemspec +++ b/idempotent-request.gemspec @@ -9,9 +9,8 @@ Gem::Specification.new do |spec| spec.authors = ['Dmytro Zakharov'] spec.email = ['dmytro@qonto.eu'] - spec.summary = %q{Write a short summary, because Rubygems requires one.} - spec.description = %q{Write a longer description or delete this line.} - spec.homepage = "TODO: Put your gem's website or public repo URL here." + spec.summary = %q{Rack middleware ensuring at most once requests for mutating endpoints.} + spec.homepage = 'https://github.com/qonto/idempotent-request' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0").reject do |f|