Class: Api::ReviewsIo::Client

Inherits:
Object
  • Object
show all
Defined in:
app/services/api/reviews_io/client.rb

Overview

Thin HTTP client for interacting with the Reviews.io API.

Defined Under Namespace

Classes: Error, MissingCredentialsError

Constant Summary collapse

INVITATION_PATH =

Filesystem/URL path for invitation.

'/invitation'
PRODUCT_RATING_BATCH_PATH =

Filesystem/URL path for product rating batch.

'/product/rating-batch'
REVIEWS_PATH =

Filesystem/URL path for reviews.

'/reviews'
MERCHANT_REVIEWS_PATH =

Filesystem/URL path for merchant reviews.

'/merchant/reviews'
DEFAULT_TIMEOUT =

seconds

15

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store_id: nil, api_key: nil, base_url: nil, http: nil, logger: Rails.logger) ⇒ Client

Returns a new instance of Client.



25
26
27
28
29
30
31
32
33
# File 'app/services/api/reviews_io/client.rb', line 25

def initialize(store_id: nil, api_key: nil, base_url: nil, http: nil, logger: Rails.logger)
  @logger = logger
  @store_id = store_id || env_or_config(:store_id)
  @api_key = api_key || env_or_config(:api_key)
  @base_url = base_url || env_or_config(:api_url)
  @http = http || default_http_client

  validate_credentials!
end

Instance Attribute Details

#api_keyObject (readonly)

Returns the value of attribute api_key.



23
24
25
# File 'app/services/api/reviews_io/client.rb', line 23

def api_key
  @api_key
end

#base_urlObject (readonly)

Returns the value of attribute base_url.



23
24
25
# File 'app/services/api/reviews_io/client.rb', line 23

def base_url
  @base_url
end

#httpObject (readonly)

Returns the value of attribute http.



23
24
25
# File 'app/services/api/reviews_io/client.rb', line 23

def http
  @http
end

#loggerObject (readonly)

Returns the value of attribute logger.



23
24
25
# File 'app/services/api/reviews_io/client.rb', line 23

def logger
  @logger
end

#store_idObject (readonly)

Returns the value of attribute store_id.



23
24
25
# File 'app/services/api/reviews_io/client.rb', line 23

def store_id
  @store_id
end

Instance Method Details

#fetch_product_ratings(skus) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'app/services/api/reviews_io/client.rb', line 44

def fetch_product_ratings(skus)
  normalized_skus = normalize_skus(skus)
  return {} if normalized_skus.empty?

  response = perform_rating_request(normalized_skus)
  log_debug("Reviews.io rating response: status=#{response.status}, body=#{safe_body(response)}")
  ensure_success!(response)
  parse_response(response)
rescue HTTP::Error => e
  raise Error, "Reviews.io request failed: #{e.message}"
rescue JSON::ParserError => e
  raise Error, "Reviews.io response parse failed: #{e.message}"
end

#fetch_reviews_by_email(email, options = {}) ⇒ Hash

Returns parsed reviews response.

Parameters:

  • email (String)

    reviewer email to filter by

  • options (Hash) (defaults to: {})

    review query filters

Options Hash (options):

  • per_page (Integer)

    reviews per page

  • page (Integer)

    page number

  • types (String)

    review types filter

  • rating (Integer)

    exact rating filter

  • min_rating (Integer)

    minimum rating filter

  • max_rating (Integer)

    maximum rating filter

  • order (String)

    sort order

  • language (String)

    language filter

  • with_questions (Boolean)

    include questions

  • min_answered (Integer)

    minimum answered filter

  • tag (String)

    tag filter

Returns:

  • (Hash)

    parsed reviews response



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'app/services/api/reviews_io/client.rb', line 96

def fetch_reviews_by_email(email, options = {})
  raise ArgumentError, 'Email is required' if email.blank?
  raise MissingCredentialsError, 'API key is required for email filtering' if api_key.blank?

  query = reviews_query_params(options).merge(
    store: store_id,
    email: email.strip,
    apikey: api_key
  )

  response = http.headers(rating_headers).get(reviews_url, params: query)
  log_debug("Reviews.io reviews by email response: status=#{response.status}, body=#{safe_body(response)}")
  ensure_success!(response)

  parsed = parse_response(response)
  parsed.is_a?(Hash) ? parsed : { 'data' => parsed }
rescue HTTP::Error => e
  raise Error, "Reviews.io request failed: #{e.message}"
rescue JSON::ParserError => e
  raise Error, "Reviews.io response parse failed: #{e.message}"
end

#fetch_reviews_by_tag(tag, options = {}) ⇒ Hash

Returns parsed reviews response.

Parameters:

  • tag (String)

    tag to filter reviews by

  • options (Hash) (defaults to: {})

    review query filters

Options Hash (options):

  • per_page (Integer)

    reviews per page

  • page (Integer)

    page number

  • types (String)

    review types filter

  • rating (Integer)

    exact rating filter

  • min_rating (Integer)

    minimum rating filter

  • max_rating (Integer)

    maximum rating filter

  • order (String)

    sort order

  • language (String)

    language filter

  • with_questions (Boolean)

    include questions

  • min_answered (Integer)

    minimum answered filter

  • tag (String)

    tag filter

Returns:

  • (Hash)

    parsed reviews response



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/services/api/reviews_io/client.rb', line 132

def fetch_reviews_by_tag(tag, options = {})
  raise ArgumentError, 'Tag is required' if tag.blank?

  query = reviews_query_params(options).merge(
    store: store_id,
    tag: tag.strip,
    apikey: api_key
  )

  response = http.headers(rating_headers).get(reviews_url, params: query)
  log_debug("Reviews.io reviews by tag response: status=#{response.status}, body=#{safe_body(response)}")
  ensure_success!(response)

  parsed = parse_response(response)
  parsed.is_a?(Hash) ? parsed : { 'data' => parsed }
rescue HTTP::Error => e
  raise Error, "Reviews.io request failed: #{e.message}"
rescue JSON::ParserError => e
  raise Error, "Reviews.io response parse failed: #{e.message}"
end

#fetch_reviews_for_sku(sku, options = {}) ⇒ Hash

Returns reviews payload keyed by sku.

Parameters:

  • sku (String)

    product SKU to fetch reviews for

  • options (Hash) (defaults to: {})

    review query filters

Options Hash (options):

  • per_page (Integer)

    reviews per page

  • page (Integer)

    page number

  • types (String)

    review types filter

  • rating (Integer)

    exact rating filter

  • min_rating (Integer)

    minimum rating filter

  • max_rating (Integer)

    maximum rating filter

  • order (String)

    sort order

  • language (String)

    language filter

  • with_questions (Boolean)

    include questions

  • min_answered (Integer)

    minimum answered filter

  • tag (String)

    tag filter

Returns:

  • (Hash)

    reviews payload keyed by sku



72
73
74
75
76
77
78
79
80
# File 'app/services/api/reviews_io/client.rb', line 72

def fetch_reviews_for_sku(sku, options = {})
  normalized_sku = normalize_review_sku(sku)
  response = perform_reviews_request(normalized_sku, options)
  build_reviews_payload(response, normalized_sku)
rescue HTTP::Error => e
  raise Error, "Reviews.io request failed: #{e.message}"
rescue JSON::ParserError => e
  raise Error, "Reviews.io response parse failed: #{e.message}"
end

#queue_invitation(payload) ⇒ Object



35
36
37
38
39
40
41
42
# File 'app/services/api/reviews_io/client.rb', line 35

def queue_invitation(payload)
  response = http.headers(default_headers)
                 .post(invitation_url, json: payload)
  log_debug("Reviews.io invitation response: status=#{response.status}, body=#{safe_body(response)}")
  response
rescue HTTP::Error => e
  raise Error, "Reviews.io request failed: #{e.message}"
end