Coverage for app / services / asin_data_service.py: 83%

40 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-06 04:49 +0000

1""" 

2This module provides functionality to interact with the ASIN Data API for  

3retrieving detailed product information based on an ASIN (Amazon Standard  

4Identification Number). The `fetch_product_details` function sends a request  

5to the API and processes the response to extract meaningful product attributes,  

6such as title, authors, categories, ratings, and ISBN. The module is 

7designed to be integrated with a Flask application and requires a valid API key  

8to function. 

9""" 

10import requests 

11from flask import current_app 

12 

13from app.helpers.utilities import sanitize, sanitize_categories_flat 

14 

15 

16# Fetch the product details from the ASIN Data API 

17def fetch_product_details(asin): 

18 """ 

19 Fetches detailed product information using the ASIN Data API. 

20 

21 This function retrieves product details for a given ASIN (Amazon Standard 

22 Identification Number) by performing a GET request to the ASIN Data 

23 API. It processes the API response and extracts specific data attributes 

24 related to the product, such as the title, rating, authors, description, 

25 ISBNs, etc. The result is returned as a structured dictionary. 

26 

27 :param asin: A string representing the ASIN (Amazon Standard 

28 Identification Number) of the desired product to fetch details for. 

29 :return: A dictionary containing structured product details fetched 

30 from the API, including attributes such as title, author, image, 

31 ISBNs, categories, and more. Returns an empty dictionary 

32 if the product details are unavailable. 

33 :raises ValueError: If the API key for ASIN Data API is missing 

34 in the application configuration. 

35 :raises HTTPError: If the HTTP request to the ASIN Data API fails or 

36 returns a response with a status code indicating an error. 

37 """ 

38 # Retrieve the api_key from app.config 

39 api_key = current_app.config.get('ASIN_DATA_API_KEY') 

40 if not api_key: 

41 raise ValueError('ASIN Data API key is missing from configuration!') 

42 

43 # See https://trajectdata.com/ecommerce/asin-data-api/ 

44 api_url = current_app.config.get('ASIN_DATA_API_URL', 'https://api.asindataapi.com/request') 

45 

46 # set up the request parameters 

47 params = { 

48 'api_key': api_key, 

49 'amazon_domain': 'amazon.com', 

50 'asin': asin, 

51 'type': 'product', 

52 'output': 'json' 

53 } 

54 # make the http GET request to ASIN Data API 

55 response = requests.get(api_url, params, timeout=30) 

56 response.raise_for_status() # Raise HTTPError for bad responses (4xx and 5xx) 

57 

58 catalog_data = response.json() 

59 if catalog_data.get('product'): 59 ↛ 97line 59 didn't jump to line 97 because the condition on line 59 was always true

60 product = catalog_data.get('product') 

61 if product: 61 ↛ 97line 61 didn't jump to line 97 because the condition on line 61 was always true

62 # these attributes are simple pass-throughs 

63 attributes = [ 

64 'title', 

65 'asin', 

66 'book_description', 

67 'rating', 

68 'link', 

69 'bestsellers_rank_flat', 

70 'specifications_flat' 

71 ] 

72 return_value = {} 

73 for attribute in attributes: 

74 if product.get(attribute): 74 ↛ 73line 74 didn't jump to line 73 because the condition on line 74 was always true

75 return_value[attribute] = sanitize(product[attribute]) 

76 # Special processing attributes 

77 if product.get('authors'): 77 ↛ 79line 77 didn't jump to line 79 because the condition on line 77 was always true

78 return_value['author'] = sanitize(product['authors'][0]['name']) 

79 if product.get('categories'): 79 ↛ 82line 79 didn't jump to line 82 because the condition on line 79 was always true

80 cat_list = [c['name'] for c in product['categories'] if 'name' in c] 

81 return_value['categories_flat'] = sanitize_categories_flat(' > '.join(cat_list)) 

82 if product.get('main_image'): 82 ↛ 84line 82 didn't jump to line 84 because the condition on line 82 was always true

83 return_value['image'] = product['main_image']['link'] 

84 if product.get('specifications'): 84 ↛ 96line 84 didn't jump to line 96 because the condition on line 84 was always true

85 specs = product['specifications'] 

86 hardcover_str = next((s['value'] for s in specs if s['name'] == 'Hardcover'), None) 

87 if hardcover_str: 87 ↛ 89line 87 didn't jump to line 89 because the condition on line 87 was always true

88 return_value['hardcover'] = sanitize(hardcover_str) 

89 isbn_10_str = next((s['value'] for s in specs if s['name'] == 'ISBN-10'), None) 

90 if isbn_10_str: 90 ↛ 92line 90 didn't jump to line 92 because the condition on line 90 was always true

91 return_value['isbn_10'] = sanitize(isbn_10_str) 

92 isbn_13_str = next((s['value'] for s in specs if s['name'] == 'ISBN-13'), None) 

93 if isbn_13_str: 93 ↛ 96line 93 didn't jump to line 96 because the condition on line 93 was always true

94 return_value['isbn_13'] = sanitize(isbn_13_str) 

95 

96 return return_value 

97 return {} # empty if errors