fulfil-io 0.4.8 → 0.5.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/CHANGELOG.md +4 -0
- data/README.md +42 -4
- data/lib/fulfil/client.rb +20 -11
- data/lib/fulfil/error.rb +27 -0
- data/lib/fulfil/interactive_report.rb +1 -1
- data/lib/fulfil/response_handler.rb +52 -0
- data/lib/fulfil/response_parser.rb +2 -3
- data/lib/fulfil/version.rb +1 -1
- data/lib/fulfil.rb +4 -1
- metadata +18 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 1100e113c9323c0fa742ece65d8a41923c060c382b1b97ad6c50ad20c550b5a9
         | 
| 4 | 
            +
              data.tar.gz: 80535f7bea24218d958812bbd8e4ab789ce966c346e5dfa891369160fc04e536
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b1ea6e403ab80bb108a90dff5f7ad58c39c228ed610ce497c631b5ae45a3ef5d2912100acd95ee33d7f2aa7c5609b71300c7a2322e1b2efcec688646573bf8da
         | 
| 7 | 
            +
              data.tar.gz: d63d23350f0775bac73f28fdbabd0645798ed28a0466e7851ade38328a9f17e7a75982bc6bada6c1d951e4eb3ed0a4ffd872c79a6dc3c848f4308ddcfd11db16
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -129,10 +129,48 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run | |
| 129 129 | 
             
            `rake test` to run the tests. You can also run `bin/console` for an interactive
         | 
| 130 130 | 
             
            prompt that will allow you to experiment.
         | 
| 131 131 |  | 
| 132 | 
            -
            To install this gem onto your local machine, run `bundle exec rake install`. | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 132 | 
            +
            To install this gem onto your local machine, run `bundle exec rake install`.
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            ### Release a new version
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            We're following semver for the release process of this gem. Make sure to apply the correct semver version for a new release.
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            To release a new version, run the `bin/release x.x.x`. That's it.
         | 
| 139 | 
            +
             | 
| 140 | 
            +
            > **NOTE:** You don't have to add a v to the version you want to release. The release script will handle that for you.
         | 
| 141 | 
            +
             | 
| 142 | 
            +
            ### Testing
         | 
| 143 | 
            +
             | 
| 144 | 
            +
            For non-client tests, create the test class or case.
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            For client tests, you'll need to add a couple steps. If running against a real
         | 
| 147 | 
            +
            backend, you'll need to provide a couple of environment variables:
         | 
| 148 | 
            +
            `FULFIL_SUBDOMAIN` and `FULFIL_TOKEN`. Additionally, pass `debug: true` to the
         | 
| 149 | 
            +
            client instance in the test. This will output the response body. Webmock will
         | 
| 150 | 
            +
            probably complain that real requests aren't allowed at this point, offering you
         | 
| 151 | 
            +
            the stub. We don't need most of that.
         | 
| 152 | 
            +
             | 
| 153 | 
            +
            We will need to capture the response body as JSON and store it in the
         | 
| 154 | 
            +
            `test/fixtures` directory. Formatted for readability, please. You'll also need
         | 
| 155 | 
            +
            to make note of the path and body of the request. Once you have that, you can
         | 
| 156 | 
            +
            generate your stub.
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            To stub a request, use (or create) the helper method based on the verb. For
         | 
| 159 | 
            +
            example, to stub a `GET` request, use `stub_fulfil_get`. Here's an example:
         | 
| 160 | 
            +
             | 
| 161 | 
            +
            ```ruby
         | 
| 162 | 
            +
            def test_find_one
         | 
| 163 | 
            +
              stub_fulfil_get('sale.sale/213112', 'sale_sale')
         | 
| 164 | 
            +
             | 
| 165 | 
            +
              client = Fulfil::Client.new
         | 
| 166 | 
            +
              response = client.find_one(model: 'sale.sale', id: 213_112)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              assert_equal 213_112, response['id']
         | 
| 169 | 
            +
            end
         | 
| 170 | 
            +
            ```
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            `stub_fulfil_get` takes two arguments: the URL path (after `/api/v2/model/`)
         | 
| 173 | 
            +
            and the fixture file name to be returned.
         | 
| 136 174 |  | 
| 137 175 | 
             
            ## Contributing
         | 
| 138 176 |  | 
    
        data/lib/fulfil/client.rb
    CHANGED
    
    | @@ -10,6 +10,12 @@ module Fulfil | |
| 10 10 | 
             
              OAUTH_TOKEN = ENV['FULFIL_TOKEN']
         | 
| 11 11 |  | 
| 12 12 | 
             
              class Client
         | 
| 13 | 
            +
                class InvalidClientError < StandardError
         | 
| 14 | 
            +
                  def message
         | 
| 15 | 
            +
                    'Client is not configured correctly.'
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 13 19 | 
             
                class NotAuthorizedError < StandardError; end
         | 
| 14 20 |  | 
| 15 21 | 
             
                class UnknownHTTPError < StandardError; end
         | 
| @@ -24,6 +30,16 @@ module Fulfil | |
| 24 30 | 
             
                  @debug = debug
         | 
| 25 31 | 
             
                  @headers = headers
         | 
| 26 32 | 
             
                  @headers.delete('X-API-KEY') if @token
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  raise InvalidClientError if invalid?
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def invalid?
         | 
| 38 | 
            +
                  @subdomain.nil? || @subdomain.empty?
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def valid?
         | 
| 42 | 
            +
                  !invalid?
         | 
| 27 43 | 
             
                end
         | 
| 28 44 |  | 
| 29 45 | 
             
                def find(model:, ids: [], id: nil, fields: %w[id rec_name])
         | 
| @@ -125,19 +141,12 @@ module Fulfil | |
| 125 141 | 
             
                end
         | 
| 126 142 |  | 
| 127 143 | 
             
                def request(endpoint:, verb: :get, **args)
         | 
| 144 | 
            +
                  raise InvalidClientError if invalid?
         | 
| 145 | 
            +
             | 
| 128 146 | 
             
                  response = client.request(verb, endpoint, args)
         | 
| 147 | 
            +
                  Fulfil::ResponseHandler.new(response).verify!
         | 
| 129 148 |  | 
| 130 | 
            -
                   | 
| 131 | 
            -
                    response.parse
         | 
| 132 | 
            -
                  elsif response.code == 204
         | 
| 133 | 
            -
                    []
         | 
| 134 | 
            -
                  elsif response.code == 401
         | 
| 135 | 
            -
                    error = response.parse
         | 
| 136 | 
            -
                    raise NotAuthorizedError, "Not authorized: #{error['error']}: #{error['error_description']}"
         | 
| 137 | 
            -
                  else
         | 
| 138 | 
            -
                    puts response.body.to_s
         | 
| 139 | 
            -
                    raise Error, 'Error encountered while processing response:'
         | 
| 140 | 
            -
                  end
         | 
| 149 | 
            +
                  response.parse
         | 
| 141 150 | 
             
                rescue HTTP::Error => e
         | 
| 142 151 | 
             
                  puts e
         | 
| 143 152 | 
             
                  raise UnknownHTTPError, 'Unhandled HTTP error encountered'
         | 
    
        data/lib/fulfil/error.rb
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Fulfil
         | 
| 4 | 
            +
              class Error < StandardError; end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              # The `Fulfil::HttpError` is raised whenever an API request returns a 400+ HTTP status code.
         | 
| 7 | 
            +
              # See `Fulfil::ResponseHandler` for more information.
         | 
| 8 | 
            +
              class HttpError < Error
         | 
| 9 | 
            +
                attr_reader :metadata
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(message, metadata = {})
         | 
| 12 | 
            +
                  @metadata = metadata
         | 
| 13 | 
            +
                  super(message)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                class BadRequest < HttpError; end
         | 
| 17 | 
            +
                class AuthorizationRequired < HttpError; end
         | 
| 18 | 
            +
                class PaymentRequired < HttpError; end
         | 
| 19 | 
            +
                class Forbidden < HttpError; end
         | 
| 20 | 
            +
                class NotFound < HttpError; end
         | 
| 21 | 
            +
                class MethodNotAllowed < HttpError; end
         | 
| 22 | 
            +
                class NotAccepted < HttpError; end
         | 
| 23 | 
            +
                class UnprocessableEntity < HttpError; end
         | 
| 24 | 
            +
                class TooManyRequests < HttpError; end
         | 
| 25 | 
            +
                class InternalServerError < HttpError; end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Fulfil
         | 
| 4 | 
            +
              # The `Fulfil::ResponseHandler` is parses the HTTP response from Fulfil. If it
         | 
| 5 | 
            +
              # encounters an HTTP status code that indicates an error, it will raise an internal
         | 
| 6 | 
            +
              # exception that the consumer can catch.
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # @example
         | 
| 9 | 
            +
              #   Fulfil::ResponseHandler.new(@response).verify!
         | 
| 10 | 
            +
              #   => true
         | 
| 11 | 
            +
              #
         | 
| 12 | 
            +
              #   Fulfil::ResponseHandler.new(@response).verify!
         | 
| 13 | 
            +
              #   => Fulfil::Error::BadRequest
         | 
| 14 | 
            +
              class ResponseHandler
         | 
| 15 | 
            +
                HTTP_ERROR_CODES = {
         | 
| 16 | 
            +
                  400 => Fulfil::HttpError::BadRequest,
         | 
| 17 | 
            +
                  401 => Fulfil::HttpError::AuthorizationRequired,
         | 
| 18 | 
            +
                  402 => Fulfil::HttpError::PaymentRequired,
         | 
| 19 | 
            +
                  403 => Fulfil::HttpError::Forbidden,
         | 
| 20 | 
            +
                  404 => Fulfil::HttpError::NotFound,
         | 
| 21 | 
            +
                  405 => Fulfil::HttpError::MethodNotAllowed,
         | 
| 22 | 
            +
                  406 => Fulfil::HttpError::NotAccepted,
         | 
| 23 | 
            +
                  422 => Fulfil::HttpError::UnprocessableEntity,
         | 
| 24 | 
            +
                  429 => Fulfil::HttpError::TooManyRequests,
         | 
| 25 | 
            +
                  500 => Fulfil::HttpError::InternalServerError
         | 
| 26 | 
            +
                }.freeze
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def initialize(response)
         | 
| 29 | 
            +
                  @response = response
         | 
| 30 | 
            +
                  @status_code = response.code
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def verify!
         | 
| 34 | 
            +
                  return true unless @status_code >= 400
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  raise HTTP_ERROR_CODES.fetch(@status_code, Fulfil::HttpError).new(
         | 
| 37 | 
            +
                    response_body['error_description'],
         | 
| 38 | 
            +
                    {
         | 
| 39 | 
            +
                      body: @response.body,
         | 
| 40 | 
            +
                      headers: @response.headers,
         | 
| 41 | 
            +
                      status: @response.status
         | 
| 42 | 
            +
                    }
         | 
| 43 | 
            +
                  )
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                private
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def response_body
         | 
| 49 | 
            +
                  @response_body ||= @response.parse
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -41,7 +41,7 @@ module Fulfil | |
| 41 41 | 
             
                def self.group(key_value_tuples)
         | 
| 42 42 | 
             
                  key_value_tuples
         | 
| 43 43 | 
             
                    .group_by { |kv_tuple| kv_tuple[0][0] }
         | 
| 44 | 
            -
                    .map  | 
| 44 | 
            +
                    .map do |group_key, kv_tuples|
         | 
| 45 45 | 
             
                    if kv_tuples.length == 1
         | 
| 46 46 | 
             
                      [group_key, mapped_value_field(value: kv_tuples[0][1])]
         | 
| 47 47 | 
             
                    else
         | 
| @@ -49,7 +49,7 @@ module Fulfil | |
| 49 49 | 
             
                      attrs = kv_tuples[1..-1].map { |tuple| [tuple[0][1..-1], tuple[1]] }
         | 
| 50 50 | 
             
                      [group_key, [['id', id[1]]].concat(group(attrs)).to_h]
         | 
| 51 51 | 
             
                    end
         | 
| 52 | 
            -
                   | 
| 52 | 
            +
                  end
         | 
| 53 53 | 
             
                end
         | 
| 54 54 |  | 
| 55 55 | 
             
                def self.parse(item:)
         | 
| @@ -57,5 +57,4 @@ module Fulfil | |
| 57 57 | 
             
                  group(key_value_tuples).to_h
         | 
| 58 58 | 
             
                end
         | 
| 59 59 | 
             
              end
         | 
| 60 | 
            -
             | 
| 61 60 | 
             
            end
         | 
    
        data/lib/fulfil/version.rb
    CHANGED
    
    
    
        data/lib/fulfil.rb
    CHANGED
    
    | @@ -1,9 +1,12 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'fulfil/version'
         | 
| 4 | 
            +
            require 'fulfil/error'
         | 
| 2 5 | 
             
            require 'fulfil/client'
         | 
| 3 6 | 
             
            require 'fulfil/model'
         | 
| 4 7 | 
             
            require 'fulfil/interactive_report'
         | 
| 8 | 
            +
            require 'fulfil/response_handler'
         | 
| 5 9 | 
             
            require 'fulfil/response_parser'
         | 
| 6 10 |  | 
| 7 11 | 
             
            module Fulfil
         | 
| 8 | 
            -
              class Error < StandardError; end
         | 
| 9 12 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: fulfil-io
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Chris Moore
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire:
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2021- | 
| 12 | 
            +
            date: 2021-12-26 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: http
         | 
| @@ -95,6 +95,20 @@ dependencies: | |
| 95 95 | 
             
                - - ">="
         | 
| 96 96 | 
             
                  - !ruby/object:Gem::Version
         | 
| 97 97 | 
             
                    version: '0'
         | 
| 98 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 99 | 
            +
              name: webmock
         | 
| 100 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 101 | 
            +
                requirements:
         | 
| 102 | 
            +
                - - ">="
         | 
| 103 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 104 | 
            +
                    version: '0'
         | 
| 105 | 
            +
              type: :development
         | 
| 106 | 
            +
              prerelease: false
         | 
| 107 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 108 | 
            +
                requirements:
         | 
| 109 | 
            +
                - - ">="
         | 
| 110 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 111 | 
            +
                    version: '0'
         | 
| 98 112 | 
             
            description:
         | 
| 99 113 | 
             
            email:
         | 
| 100 114 | 
             
            - chris@knowndecimal.com
         | 
| @@ -111,9 +125,11 @@ files: | |
| 111 125 | 
             
            - Rakefile
         | 
| 112 126 | 
             
            - lib/fulfil.rb
         | 
| 113 127 | 
             
            - lib/fulfil/client.rb
         | 
| 128 | 
            +
            - lib/fulfil/error.rb
         | 
| 114 129 | 
             
            - lib/fulfil/interactive_report.rb
         | 
| 115 130 | 
             
            - lib/fulfil/model.rb
         | 
| 116 131 | 
             
            - lib/fulfil/query.rb
         | 
| 132 | 
            +
            - lib/fulfil/response_handler.rb
         | 
| 117 133 | 
             
            - lib/fulfil/response_parser.rb
         | 
| 118 134 | 
             
            - lib/fulfil/version.rb
         | 
| 119 135 | 
             
            homepage: https://github.com/knowndecimal/fulfil
         |