README.md in paypal-rest-api-0.0.4 vs README.md in paypal-rest-api-0.1.0

- old
+ new

@@ -6,15 +6,18 @@ bundle add paypal-rest-api ``` ## Features +- Supported Ruby 2.6 - current Head - No dependencies; - Automatic authorization & reauthorization; - Auto-retries (configured); - Automatically added Paypal-Request-Id header for idempotent requests if not provided; +- Webhooks Offline verification (needs to download certificate once) +- Custom callbacks before/after request ## Usage There are two options: @@ -69,23 +72,23 @@ response = PaypalAPI.delete(path, query: query, body: body, headers: headers) ``` ### Parsing response -`response.body` is a main method that returns parsed JSON respoonse as a HASH. +`response.body` is a main method that returns parsed JSON respoonse as a Hash. There are also many others helpful methods: -``` +```ruby response.body # Parsed JSON. JSON is parsed lazyly, keys are symbolized. response[:foo] # Gets :foo attribute from parsed body response.fetch(:foo) # Fetches :foo attribute from parsed body response.http_response # original Net::HTTP::Response response.http_body # original response string response.http_status # Integer http status response.http_headers # Hash with response headers (keys are strings) -response.requested_at # Time when request was sent +response.request # Request that generates this response ``` ## Configuration options PaypalAPI client accepts this additional options: `:live`, `:retries`, `:http_opts` @@ -132,9 +135,111 @@ ```ruby client = PaypalAPI::Client.new( http_opts: {read_timeout: 30, write_timeout: 30, open_timeout: 30} # ... ) +``` + +## Webhoooks verification + +Webhooks can be verified [offline](https://developer.paypal.com/api/rest/webhooks/rest/#link-selfverificationmethod) +or [online](https://developer.paypal.com/api/rest/webhooks/rest/#link-postbackmethod). +Method `PaypalAPI.verify_webhook(webhook_id:, headers:, raw_body:)` +verifies webhook. It to verify webhook OFFLINE and it fallbacks +to ONLINE if offline verification returns false to be sure you don't miss a +valid webhook. + +When some required header is missing it will raise +`PaypalAPI::WebhooksVerifier::MissingHeader` error. + +Example of Rails controller with webhook verification: + +```ruby +class Webhooks::PaypalController < ApplicationController + def create + # PayPal registered webhook ID for current URL + webhook_id = ENV['PAYPAL_WEBHOOK_ID'] + headers = request.headers # must be a Hash + raw_body = request.raw_post # must be a raw String body + + webhook_is_valid = PaypalAPI.verify_webhook( + webhook_id: webhook_id, + headers: headers, + raw_body: raw_body + ) + + if webhook_is_valid + handle_valid_webhook_event(body) + else + handle_invalid_webhook_event(webhook_id, headers, body) + end + + head :no_content + end +end +``` + +## Callbacks + +Callbacks list: + +- `:before` - Runs before request +- `:after_success` - Runs after getting successful response +- `:after_fail` - Runs after getting failed response (non-2xx) status code +- `:after_network_error` - Runs after getting network error + +Callbacks are registered on `client` object. + +Each callback receive `request` and `context` variables. +`context` can be modified manually to save state between callbacks. + +`:after_success` and `:after_fail` callbacks have additional `response` argument + +`:after_network_error` callback has additional `error` argument + +```ruby +PaypalAPI.client.add_callback(:before) do |request, context| + context[:request_id] = SecureRandom.hex(3) + context[:starts_at] = Process.clock_gettime(Process::CLOCK_MONOTONIC) +end + +PaypalAPI.client.add_callback(:after) do |request, context, response| + ends_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + duration = ends_at - context[:starts_at] + + SomeLogger.debug( + 'PaypalAPI success request', + method: request.method, + uri: request.uri.to_s, + duration: duration + ) +end + +PaypalAPI.client.add_callback(:after_fail) do |request, context, response| + SomeLogger.error( + 'PaypalAPI request failed', + method: request.method, + uri: request.uri.to_s, + response_status: response.http_status, + response_body: response.http_body, + will_retry: context[:will_retry], + retry_number: context[:retry_number], + retry_count: context[:retry_count] + ) +end + +PaypalAPI.client.add_callback(:after_network_error) do |request, context, error| + SomeLogger.error( + 'PaypalAPI network connection error' + method: request.method, + uri: request.uri.to_s, + error: error.message, + paypal_request_id: request.headers['paypal-request-id'], + will_retry: context[:will_retry], + retry_number: context[:retry_number], + retry_count: context[:retry_count] + ) +end ``` ## Errors All APIs can raise error in case of network error or non-2xx response status code.