best_buy_ruby 0.1.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 +7 -0
- data/.gitignore +21 -0
- data/.reek.yml +127 -0
- data/.rspec +3 -0
- data/.rubocop.yml +74 -0
- data/.travis.yml +33 -0
- data/CHANGELOG.md +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +83 -0
- data/Rakefile +6 -0
- data/best_buy_ruby.gemspec +42 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/docs/categories_api.md +25 -0
- data/docs/general_overview.md +67 -0
- data/docs/products_api.md +85 -0
- data/docs/stores_api.md +68 -0
- data/lib/best_buy.rb +34 -0
- data/lib/best_buy/base.rb +13 -0
- data/lib/best_buy/base/version.rb +7 -0
- data/lib/best_buy/base_api.rb +46 -0
- data/lib/best_buy/categories.rb +23 -0
- data/lib/best_buy/config.rb +17 -0
- data/lib/best_buy/helpers/api_helper.rb +13 -0
- data/lib/best_buy/helpers/conditions/category_condition.rb +19 -0
- data/lib/best_buy/helpers/conditions/max_price_condition.rb +19 -0
- data/lib/best_buy/helpers/conditions/min_price_condition.rb +19 -0
- data/lib/best_buy/helpers/conditions/new_condition.rb +19 -0
- data/lib/best_buy/helpers/conditions/pre_owned_condition.rb +19 -0
- data/lib/best_buy/helpers/conditions/refurbished_condition.rb +19 -0
- data/lib/best_buy/models/address.rb +23 -0
- data/lib/best_buy/models/base_category.rb +12 -0
- data/lib/best_buy/models/category.rb +20 -0
- data/lib/best_buy/models/collection_header.rb +20 -0
- data/lib/best_buy/models/collections_response.rb +19 -0
- data/lib/best_buy/models/image.rb +16 -0
- data/lib/best_buy/models/offer.rb +18 -0
- data/lib/best_buy/models/product.rb +39 -0
- data/lib/best_buy/models/shipping_level_of_service.rb +13 -0
- data/lib/best_buy/models/store.rb +26 -0
- data/lib/best_buy/products.rb +53 -0
- data/lib/best_buy/search_query_builder.rb +21 -0
- data/lib/best_buy/stores.rb +30 -0
- data/lib/generators/best_buy/config/config_generator.rb +13 -0
- data/lib/generators/best_buy/config/templates/config.rb +5 -0
- metadata +234 -0
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/best_buy/base/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'best_buy_ruby'
|
7
|
+
spec.version = BestBuy::Base::VERSION
|
8
|
+
spec.authors = ['Sandro Damilano']
|
9
|
+
spec.email = ['sandro.damilano@rootstrap.com']
|
10
|
+
|
11
|
+
spec.summary = 'A wrapper for Best Buy APIs.'
|
12
|
+
spec.homepage = 'https://github.com/rootstrap/best_buy_ruby'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/rootstrap/best_buy_ruby'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://github.com/rootstrap/best_buy_ruby'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
spec.bindir = 'exe'
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
# Production dependencies
|
30
|
+
spec.add_dependency 'activesupport', '~> 6.0.2.1'
|
31
|
+
spec.add_dependency 'faraday', '~> 1.0.0'
|
32
|
+
|
33
|
+
# Development dependencies
|
34
|
+
spec.add_development_dependency 'ammeter'
|
35
|
+
spec.add_development_dependency 'railties'
|
36
|
+
spec.add_development_dependency 'rake'
|
37
|
+
spec.add_development_dependency 'reek'
|
38
|
+
spec.add_development_dependency 'rspec'
|
39
|
+
spec.add_development_dependency 'rubocop'
|
40
|
+
spec.add_development_dependency 'simplecov'
|
41
|
+
spec.add_development_dependency 'webmock'
|
42
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'best_buy_ruby/base'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Categories API
|
2
|
+
|
3
|
+
## The Category object
|
4
|
+
|
5
|
+
Attributes:
|
6
|
+
|
7
|
+
- `id`: Used to find all results within a specific category (e.g., 'abcat0100000')
|
8
|
+
- `name`: Used to find all subcategories (e.g., parents, siblings, children) within a specific category
|
9
|
+
- `url`: URL to corresponding BESTBUY.COM category page
|
10
|
+
- `active`: Indicates if the category is currently active or not
|
11
|
+
- `path`: Array of parent categories, starting with the root and finishing with the present one
|
12
|
+
- `sub_categories`: Array of child categories. Each one is a [BaseCategory](categories_api.md#the-basecategory-object) object
|
13
|
+
|
14
|
+
#### The BaseCategory object
|
15
|
+
|
16
|
+
A minimalistic version of a category. Used to represent the categories in occasions where not the whole information is available (like the categories returned as `sub_categories`)
|
17
|
+
|
18
|
+
Attributes:
|
19
|
+
|
20
|
+
- `id`: Used to find all results within a specific category (e.g., abcat0100000)
|
21
|
+
- `name`: Used to find all subcategories (e.g., parents, siblings, children) within a specific category
|
22
|
+
|
23
|
+
## Interface
|
24
|
+
|
25
|
+
(For more methods, check the [common API interface](general_overview.md#common-methods))
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# General Overview
|
2
|
+
|
3
|
+
The different APIs accessible by this gem are:
|
4
|
+
|
5
|
+
- [Products](products_api.md)
|
6
|
+
- [Stores](stores_api.md)
|
7
|
+
- [Categories](categories_api.md)
|
8
|
+
|
9
|
+
In spite of having each their own specification, they all share some basics listed here.
|
10
|
+
|
11
|
+
## Common interface
|
12
|
+
|
13
|
+
This method can be used with any of the APIs:
|
14
|
+
|
15
|
+
#### `get_all(search_query:, pagination:)`
|
16
|
+
_alias: `index`_
|
17
|
+
|
18
|
+
Retrieves a collection of items (these depend on the API). These items will be filtered by `search_query` and limited by `pagination`.
|
19
|
+
|
20
|
+
Params:
|
21
|
+
|
22
|
+
- `search_query`: A string representing the query added to the URL to filter the items (See [Search Techniques](https://bestbuyapis.github.io/api-documentation/#search-techniques) in the Best Buy API reference). Optional.
|
23
|
+
- `pagination`: See [Pagination](general_overview.md#pagination). Optional.
|
24
|
+
|
25
|
+
Returns: a [`CollectionsResponse`](general_overview.md#collections-response) object
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
search_query = '(active=true)'
|
29
|
+
pagination_params = { page: 2, page_size: 20 }
|
30
|
+
|
31
|
+
BestBuy::Categories.new(your_api_key).get_all(search_query: search_query, pagination: pagination_params)
|
32
|
+
```
|
33
|
+
|
34
|
+
## Collections response
|
35
|
+
|
36
|
+
Every request made that returns a collection of items (no matter what *kind* of item) will return an object called `CollectionsResponse`. This object contains two attributes:
|
37
|
+
|
38
|
+
- `header`
|
39
|
+
- `collection`
|
40
|
+
|
41
|
+
The `collection` will contain a list of objects of the requested collection (`Product`, `Store`, etc).
|
42
|
+
|
43
|
+
The `header` will be a `CollectionHeader` object which will contain some metadata of the request itself. Its attributes include:
|
44
|
+
|
45
|
+
- `canonical_url`: the non-server part of the query
|
46
|
+
- `current_page`: the page being returned
|
47
|
+
- `partial`: flag indicating whether or not the query returned only partial results (in the event of a timeout)
|
48
|
+
- `from`: the index of the first item returned on the current page
|
49
|
+
- `to`: the index of the last item returned on the current page
|
50
|
+
- `total`: the total number of items returned by the query
|
51
|
+
- `total_pages`: the number of pages required to list all items
|
52
|
+
- `query_time`: the time required to search the database
|
53
|
+
- `total_time`: the time required to parse, search, format and return results
|
54
|
+
|
55
|
+
## Pagination
|
56
|
+
|
57
|
+
Best Buy APIs accept pagination parameters to control the amount of results returned. That's why for the `get_all` method, for example, there's an optional `pagination` parameter, which consists of a hash with two also optional keys:
|
58
|
+
|
59
|
+
- `:page`: number of the page of results you’d like returned
|
60
|
+
- `:page_size`: amount of results per page (default: 10, max: 100)
|
61
|
+
|
62
|
+
Example:
|
63
|
+
```ruby
|
64
|
+
pagination_params = { page: 3, page_size: 50 }
|
65
|
+
|
66
|
+
BestBuy::Stores.new(your_api_key).get_all(pagination: pagination_params)
|
67
|
+
```
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Products API
|
2
|
+
|
3
|
+
## The Product object
|
4
|
+
|
5
|
+
Attributes:
|
6
|
+
|
7
|
+
- `active`: Identifies if product is currently supported in the BESTBUY.COM catalog
|
8
|
+
- `category_path`: A hierarchical view of a product returned as a collection
|
9
|
+
- `alternate_categories`: Alternative categories of the product
|
10
|
+
- `images`: An array of [Images](products_api.md#the-image-object)
|
11
|
+
- `name`: Product name
|
12
|
+
- `offers`: An array of [Offers](products_api.md#the-offer-object)
|
13
|
+
- `regular_price`: Product’s regular selling price
|
14
|
+
- `sale_price`: Current item selling price
|
15
|
+
- `shipping_cost`: Provides product’s lowest shipping costs
|
16
|
+
- `shipping_levels_of_service`: An array of [Shipping levels of service](products_api.md#the-shippinglevelofservice-object)
|
17
|
+
- `sku`: Best Buy unique 7-digit product identifier
|
18
|
+
- `type`: Best Buy product type. See [Product type details](https://bestbuyapis.github.io/api-documentation/#listing-products) in the Best Buy API reference for further information
|
19
|
+
- `upc`: Universal Product Code (UPC)
|
20
|
+
- `url`: URL to BESTBUY.COM product detail page
|
21
|
+
- `raw_attributes`: Hash containing all information returned by the Best Buy API about the product. Any attribute returned not present in the object can be found here.
|
22
|
+
|
23
|
+
#### The Image object
|
24
|
+
|
25
|
+
Attributes:
|
26
|
+
|
27
|
+
- `height`: Height of the image
|
28
|
+
- `width`: Width of the image
|
29
|
+
- `unit_of_measure`: Unit in which height and width are expressed
|
30
|
+
- `href`: URL of the image
|
31
|
+
- `primary`: If it's the main image or not
|
32
|
+
- `rel`: Name of the image
|
33
|
+
|
34
|
+
#### The Offer object
|
35
|
+
|
36
|
+
Attributes:
|
37
|
+
|
38
|
+
- `id`: Offer identifier
|
39
|
+
- `offer_name`: Offer name
|
40
|
+
- `content_notes`: Notes about the offer
|
41
|
+
- `start_date`: Offer start date
|
42
|
+
- `end_date`: Offer end date
|
43
|
+
- `text`: Offer description
|
44
|
+
- `type`: Offer types can include: special_offer, digital_insert and deal_of_the_day (See the [oficial documentation](https://bestbuyapis.github.io/api-documentation/#offers-and-deals) for further info)
|
45
|
+
- `url`: URL of offer information on BESTBUY.COM
|
46
|
+
|
47
|
+
#### The ShippingLevelOfService object
|
48
|
+
|
49
|
+
Represents the shipping options of the product, with their own prices.
|
50
|
+
|
51
|
+
Attributes:
|
52
|
+
|
53
|
+
- `service_level_id`: ID of the shipping level of service
|
54
|
+
- `service_level_name`: Name of the shipping level of service
|
55
|
+
- `unit_shipping_price`: Price of the shipping level of service
|
56
|
+
|
57
|
+
## Interface
|
58
|
+
|
59
|
+
(For more methods, check the [common API interface](general_overview.md#common-methods))
|
60
|
+
|
61
|
+
#### `get_by(conditions)`
|
62
|
+
|
63
|
+
Params:
|
64
|
+
|
65
|
+
- `conditions`: A hash including certain search conditions. All of them are optional.
|
66
|
+
|
67
|
+
- `:category_id`: The ID of a category. Returns only products of that category.
|
68
|
+
- `:min_price`: Minimum price allowed for the returned products. It will take into account products on sale.
|
69
|
+
- `:max_price`: Maximum price allowed for the returned products. It will take into account products on sale.
|
70
|
+
- `:item_condition`: The condition all returned products must have. Can be either `new`, `pre-owned` or `refurbished`.
|
71
|
+
- `:pagination`: See [Pagination](general_overview.md#pagination)
|
72
|
+
|
73
|
+
Returns: a [`CollectionsResponse`](general_overview.md#collections-response) object
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
conditions = {
|
77
|
+
category_id: 'cat02015',
|
78
|
+
min_price: 10,
|
79
|
+
max_price: 15,
|
80
|
+
item_condition: 'new',
|
81
|
+
pagination: { page: 4, page_size: 100 }
|
82
|
+
}
|
83
|
+
|
84
|
+
BestBuy::Products.new(your_api_key).get_by(conditions)
|
85
|
+
```
|
data/docs/stores_api.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Stores API
|
2
|
+
|
3
|
+
## The Store object
|
4
|
+
|
5
|
+
Attributes:
|
6
|
+
|
7
|
+
- `location_type`: Whether the location is a Store or a Warehouse
|
8
|
+
- `long_name`: Full store name
|
9
|
+
- `name`: Store name
|
10
|
+
- `opening_time`: See [opening_time](stores_api.md#opening_time)
|
11
|
+
- `phone`: Store phone number; phone number for Express stores goes to Best Buy Customer Service
|
12
|
+
- `services`: Collection of services offered at each Best Buy store
|
13
|
+
- `store_id`: Store number
|
14
|
+
- `store_type`: Indicates the type of store, and is only present if locationType is ‘Store’. See the [official documentation](https://bestbuyapis.github.io/api-documentation/#common-attributes56) for more details
|
15
|
+
- `store_address`: See [The Address object](stores_api.md#the-address-object)
|
16
|
+
|
17
|
+
#### `opening_time`
|
18
|
+
|
19
|
+
Array of hashes containing info about the opening hours for each day for the next two weeks. It has the following keys:
|
20
|
+
|
21
|
+
- `:day`: Name of the day of the week (e.g.: 'Sunday')
|
22
|
+
- `:date`: Date of the day (string formatted as: YYYY-MM-DD)
|
23
|
+
- `:open`: Opening time (24-hour clock. E.g.: `'10:00'`. `'Close'` if the store is closed)
|
24
|
+
- `:close`: Closing time (24-hour clock. E.g.: `'21:00'`. `'Close'` if the store is closed)
|
25
|
+
|
26
|
+
#### The Address object
|
27
|
+
|
28
|
+
Object that keeps all the address information of the store.
|
29
|
+
|
30
|
+
Attributes:
|
31
|
+
|
32
|
+
- `address`: Street address
|
33
|
+
- `address2`: Street address 2 provides additional street address information for the Best Buy store in the result set
|
34
|
+
- `city`: City name
|
35
|
+
- `region`: State, territory
|
36
|
+
- `country`: Country name
|
37
|
+
- `postal_code`: 5-digit postal code
|
38
|
+
- `full_postal_code`: 9-digit postal code if available for store location
|
39
|
+
- `gmt_offset`: Time difference from GMT
|
40
|
+
- `lat`: Latitude
|
41
|
+
- `lng`: Longitude
|
42
|
+
|
43
|
+
Note: All these attributes are accessible directly by the Store object
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
store = Store.new({ address: '50 Holyoke St' })
|
47
|
+
store.address # returns '50 Holyoke St'
|
48
|
+
```
|
49
|
+
|
50
|
+
## Interface
|
51
|
+
|
52
|
+
(For more methods, check the [common API interface](general_overview.md#common-methods))
|
53
|
+
|
54
|
+
#### `find(store_id)`
|
55
|
+
|
56
|
+
Returns the store matching the requested ID.
|
57
|
+
|
58
|
+
Params:
|
59
|
+
|
60
|
+
- `store_id`: The ID of the required store
|
61
|
+
|
62
|
+
Returns: a `Store` object
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
store_id = 418
|
66
|
+
|
67
|
+
BestBuy::Stores.new(your_api_key).find(store_id)
|
68
|
+
```
|
data/lib/best_buy.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/array'
|
4
|
+
require 'active_support/core_ext/hash'
|
5
|
+
require 'active_support/core_ext/module/delegation'
|
6
|
+
require 'active_support/core_ext/string'
|
7
|
+
require 'faraday'
|
8
|
+
|
9
|
+
require 'best_buy/helpers/api_helper'
|
10
|
+
require 'best_buy/helpers/conditions/category_condition'
|
11
|
+
require 'best_buy/helpers/conditions/max_price_condition'
|
12
|
+
require 'best_buy/helpers/conditions/min_price_condition'
|
13
|
+
require 'best_buy/helpers/conditions/new_condition'
|
14
|
+
require 'best_buy/helpers/conditions/pre_owned_condition'
|
15
|
+
require 'best_buy/helpers/conditions/refurbished_condition'
|
16
|
+
|
17
|
+
require 'best_buy/base_api'
|
18
|
+
require 'best_buy/categories'
|
19
|
+
require 'best_buy/products'
|
20
|
+
require 'best_buy/search_query_builder'
|
21
|
+
require 'best_buy/stores'
|
22
|
+
|
23
|
+
require 'best_buy/models/address'
|
24
|
+
require 'best_buy/models/base_category'
|
25
|
+
require 'best_buy/models/category'
|
26
|
+
require 'best_buy/models/collection_header'
|
27
|
+
require 'best_buy/models/collections_response'
|
28
|
+
require 'best_buy/models/image'
|
29
|
+
require 'best_buy/models/offer'
|
30
|
+
require 'best_buy/models/product'
|
31
|
+
require 'best_buy/models/shipping_level_of_service'
|
32
|
+
require 'best_buy/models/store'
|
33
|
+
|
34
|
+
require 'generators/best_buy/config/config_generator'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BestBuy
|
4
|
+
class BaseAPI
|
5
|
+
# All subclasses must implement:
|
6
|
+
# :model_class
|
7
|
+
# :collection_name
|
8
|
+
# :api_url
|
9
|
+
|
10
|
+
BASE_URL = 'https://api.bestbuy.com'
|
11
|
+
|
12
|
+
attr_reader :api_key
|
13
|
+
|
14
|
+
def initialize(api_key)
|
15
|
+
@api_key = api_key
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_all(search_query: '', pagination: {})
|
19
|
+
request_params = {
|
20
|
+
apiKey: api_key,
|
21
|
+
format: 'json',
|
22
|
+
show: 'all'
|
23
|
+
}.merge(pagination)
|
24
|
+
|
25
|
+
response = APIHelper.new.parse_response(get_response(search_query, request_params))
|
26
|
+
|
27
|
+
CollectionsResponse.new(
|
28
|
+
response: response,
|
29
|
+
collection_name: collection_name,
|
30
|
+
collection_type: model_class
|
31
|
+
)
|
32
|
+
end
|
33
|
+
alias_method :index, :get_all
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def connection
|
38
|
+
@connection ||= Faraday.new(url: BaseAPI::BASE_URL)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_response(search_query, params)
|
42
|
+
url = URI.escape(api_url + search_query) # rubocop:disable Lint/UriEscapeUnescape
|
43
|
+
connection.get(url, params).body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'best_buy'
|
4
|
+
|
5
|
+
module BestBuy
|
6
|
+
class Categories < BaseAPI
|
7
|
+
CATEGORIES_API = '/v1/categories'
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def model_class
|
12
|
+
Category
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection_name
|
16
|
+
:categories
|
17
|
+
end
|
18
|
+
|
19
|
+
def api_url
|
20
|
+
CATEGORIES_API
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|