Moving to New York
During my last semester of college, I was given the opportunity to work at a startup called Ouway. The issue was I had to move to New York.
I was hesitant at first, having never lived in a big city before and being uncertain about the cost of living. However, I decided to take the chance because it was a great opportunity to work in the fashion industry and gain experience as a software engineer. After doing some research, I found a tiny studio apartment in Manhattan.
For the past year, I was working diligently, trying to bring the project to market, sadly though because of the recession I was sadly let go. However, I experience I gained during my time at Ouway was invaluable.
What was Ouway?
Ouway planned on innovating the shopping experience through a same-day delivery/return service. The focus was meeting the needs of today's consumers ensuring that they can receive their purchases on the same day they place their order, providing an exceptional level of convenience and satisfaction.
One of the main focal points of Ouway was populating the app with products that we could ensure could be delivered/returned to the customer the same day. This is where I came in! At Ouway, I was the Head of Automation & Data Crawling which meant my primary focus was to scrape data from various fashion sites and populate the Ouway app with the latest products. This was a challenging task, as each site had a different structure and required a unique approach to scrape the required data. However, I was able to successfully automate the process and ensure that the app was always up-to-date with the latest products available for same-day delivery.
API Wrappers
One method, if readable was to use the store’s internal API. If the store had a public API, most of the data contained product inventory and location data, which I would then transform for our backend to accept and populate the Ouway app. In this blogpost, I’m going go over one of the API wrappers I wrote for Best Buy.
Best Buy API
The Best Buy API provides product data, including pricing, availability, and reviews. The raw JSON data from Best Buy is transformed into an object with attributes that can be utilized. This library streamlines the API call process by taking care of query structure, GET requests, and JSON parsing in the background.
To use the Best Buy API, I wrote a Python wrapper that makes it easy to retrieve data from the API and transform it into a format that can be used by our backend. This wrapper made it possible for us to quickly add Best Buy products to the Ouway app and ensure that our customers had access to the latest products available for same-day delivery. Here’s a closer look into the wrapper:
Data Modeling
This file contains the classes that represent the objects returned by the Best Buy API. These classes define the attributes that are returned by the API and provide a convenient way to access them.
_13class Product:_13 def __init__(self, json) -> str:_13 self.sku = json.get('sku', None)_13 self.score = json.get('score', None)_13 self.productId = json.get('productId', None)_13 self.name = json.get('name', None)_13 self.source = json.get('source', None)_13 self.type = json.get('type', None)_13 self.startDate = json.get('startDate', None)_13 self.new = json.get('new', None) self.name = data['name']_13 self.description = data['longDescription']_13 self.price = data['regularPrice']_13 self.image_url = data['image']
This is an example of the Product class, which represents a product returned by the Best Buy API. The class constructor takes the raw json of data as an argument and initializes the attributes of the object. Using these classes, we can easily access the data returned by the Best Buy API and transform it into a format that can be used by our backend.
Backend
In the backend, we have a _request
function that makes a request to the Best Buy API. This function takes a query
and a category
as arguments and returns a JSON response. We also have a ProductAPI
class, along with the other API options Best Buy offers, that has several methods for searching the Best Buy product catalog based on different criteria. These methods make use of the _request
function to retrieve data from the Best Buy API.
_17def _request(query, category, sort=None):_17 """_17 Makes request to Best Buy API_17_17 Args:_17 category (str): Refers to different API categories_17 query (str): Query for the specific APIs_17 sort (str): None_17_17 Returns:_17 str: JSON response of request_17_17 """_17 return requests.get(_17 'https://api.bestbuy.com/v1/{category}{query}?apiKey={key}{sort}&format=json'.format(_17 category=category, query=query, key=api_key, sort=(_17 sort if sort else ""))).json()
The wrapper contained two main components, the Product
class and the ProductAPI
class. The Product
class represented a product returned by the Best Buy API and defined the attributes that were returned by the API. The ProductAPI
class had several methods for searching the Best Buy product catalog based on different criteria. These methods made use of the _request
function to retrieve data from the Best Buy API.
The _request
function made a request to the Best Buy API and returned a JSON response. It took a query
and a category
as arguments and was able to retrieve data from the Best Buy API based on these arguments. This function was important because it took care of query structure, GET requests, and JSON parsing in the background, making it easy to retrieve data from the Best Buy API.
_86class ProductAPI:_86_86 def _query(self, query, sort=None):_86 """_86 Private function to call API_86_86 Args:_86 query (str): Query for API_86_86 Returns:_86 list: Either a single or list of Product object(s)_86 """_86 product_list = _request(_86 query,_86 'products',_86 '&sort={0}.asc'.format(sort) if sort else None).get(_86 'products',_86 [])_86 return [Product(product) for product in product_list]_86_86 def search(self, keyword=None, **kwargs):_86 """_86 Search Best Buy Product catalog based on search Keyword(s) and product attributes_86_86 Args:_86 keyword (str): search element_86 **kwargs (str): key, value pair (product attribute, search (any))_86_86 Returns:_86 list: List of all products based on criteria_86 """_86_86 if not keyword:_86 keyword = ""_86 else:_86 keyword = '(search={})'.format(keyword)_86 if kwargs:_86 keyword += '&'_86 for key, value in kwargs.items():_86 keyword = '{s}{k}={v}&'.format(s=keyword, k=key, v=value)_86 keyword = '({})'.format(keyword[:-1])_86 return self._query(keyword)_86_86 def search_sku(self, sku, sort=None):_86 """_86 Search Best Buy Product catalog based on sku_86_86 Args:_86 sku (str): search element_86_86 Returns:_86 object: Singular Product object_86 """_86_86 try:_86 return self._query('(sku={0})'.format(str(sku)), sort)[0]_86 except IndexError:_86 return None_86_86 def search_upc(self, upc, sort=None):_86 """_86 Search Best Buy Product catalog based on upc_86_86 Args:_86 upc (str): search element_86_86 Returns:_86 object: Singular Product object_86 """_86_86 try:_86 return self._query('(upc={0})'.format(str(upc)), sort)[0]_86 except IndexError:_86 return None_86_86 def search_description(self, description, sort=None):_86 """_86 Search Best Buy Product catalog based on description_86_86 Args:_86 description (str): search element_86_86 Returns:_86 object: Singular Product object_86 """_86 return self._query('(description={0})'.format(description), sort=None)
Using API wrappers like this one allowed us to quickly and easily populate the Ouway app with the latest products available for same-day delivery, and ensured that our customers always had access to the most up-to-date information.
Conclusion
Though my time at Ouway was not as long as I first anticipated, it was an important stepping stone in my career and I will always be grateful for the experience. I am eagerly looking forward to continuing this project in the near future. I have already begun brainstorming new ideas and exploring different approaches that could potentially take this project to the next level. Overall, I am confident that this project has a lot of potential and I am excited to see where it goes in the coming months.