best_buy_ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|