Class: RESO::API::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/reso_api/app/models/reso/api/client.rb

Constant Summary collapse

RESOURCE_KEYS =
{
  media: "MediaKey",
  members: "MemberKey",
  offices: "OfficeKey",
  properties: "ListingKey"
}
DETAIL_ENDPOINTS =
{
  medium: "/Media",
  member: "/Member",
  office: "/Office",
  property: "/Property"
}
FILTERABLE_ENDPOINTS =
{
  media: "/Media",
  members: "/Member",
  offices: "/Office",
  properties: "/Property"
}
PASSTHROUGH_ENDPOINTS =
{
  metadata: "/$metadata"
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**opts) ⇒ Client

Returns a new instance of Client.



12
13
14
15
# File 'lib/reso_api/app/models/reso/api/client.rb', line 12

def initialize(**opts)
  @client_id, @client_secret, @auth_url, @base_url = opts.values_at(:client_id, :client_secret, :auth_url, :base_url)
  validate!
end

Instance Attribute Details

#auth_urlObject

Returns the value of attribute auth_url.



10
11
12
# File 'lib/reso_api/app/models/reso/api/client.rb', line 10

def auth_url
  @auth_url
end

#base_urlObject

Returns the value of attribute base_url.



10
11
12
# File 'lib/reso_api/app/models/reso/api/client.rb', line 10

def base_url
  @base_url
end

#client_idObject

Returns the value of attribute client_id.



10
11
12
# File 'lib/reso_api/app/models/reso/api/client.rb', line 10

def client_id
  @client_id
end

#client_secretObject

Returns the value of attribute client_secret.



10
11
12
# File 'lib/reso_api/app/models/reso/api/client.rb', line 10

def client_secret
  @client_secret
end

Instance Method Details

#fresh_oauth2_payloadObject



115
116
117
118
119
# File 'lib/reso_api/app/models/reso/api/client.rb', line 115

def fresh_oauth2_payload
  @oauth2_payload = oauth2_client.client_credentials.get_token
  File.write(oauth2_token_path, @oauth2_payload.to_hash.to_json)
  return @oauth2_payload
end

#get_oauth2_payloadObject



129
130
131
132
133
134
135
136
137
138
# File 'lib/reso_api/app/models/reso/api/client.rb', line 129

def get_oauth2_payload
  if File.exist?(oauth2_token_path)
    persisted = File.read(oauth2_token_path)
    payload = OAuth2::AccessToken.from_hash(oauth2_client, JSON.parse(persisted))
  else
    payload = oauth2_client.client_credentials.get_token
    File.write(oauth2_token_path, payload.to_hash.to_json)
  end
  return payload
end

#oauth2_clientObject



92
93
94
95
96
97
98
99
100
# File 'lib/reso_api/app/models/reso/api/client.rb', line 92

def oauth2_client
  OAuth2::Client.new(
    client_id,
    client_secret,
    token_url: auth_url,
    scope: "api",
    grant_type: "client_credentials"
  )
end

#oauth2_payloadObject



125
126
127
# File 'lib/reso_api/app/models/reso/api/client.rb', line 125

def oauth2_payload
  @oauth2_payload ||= get_oauth2_payload
end

#oauth2_tokenObject



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/reso_api/app/models/reso/api/client.rb', line 102

def oauth2_token
  payload = oauth2_payload
  token = JWT.decode(payload.token, nil, false)
  exp_timestamp = Hash(token.try(:first))["exp"].to_s
  expiration = DateTime.strptime(exp_timestamp, '%s').utc rescue DateTime.now.utc
  if expiration > DateTime.now.utc
    return payload.token
  else
    @oauth2_payload = fresh_oauth2_payload
    return @oauth2_payload.token
  end
end

#oauth2_token_pathObject



121
122
123
# File 'lib/reso_api/app/models/reso/api/client.rb', line 121

def oauth2_token_path
  File.join(Dir.tmpdir, [base_url.parameterize, "-oauth-token.json"].join)
end

#perform_call(endpoint, params) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/reso_api/app/models/reso/api/client.rb', line 144

def perform_call(endpoint, params)
  uri = uri_for_endpoint(endpoint)
  retries = 0
  if params.present?
    query = params.present? ? URI.encode_www_form(params).gsub("+", " ") : ""
    uri.query && uri.query.length > 0 ? uri.query += '&' + query : uri.query = query
    return URI::decode(uri.request_uri) if params.dig(:$debug).present?
  end
  begin
    req = Net::HTTP::Get.new(uri.request_uri)
    req['Authorization'] = "Bearer #{oauth2_token}"
    res = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
      http.request(req)
    end
    response = JSON(res.body) rescue res.body
    if response.is_a?(String) && response.include?('Bad Gateway')
      raise StandardError
    elsif response.is_a?(String) && response.include?('Unauthorized')
      fresh_oauth2_payload
      raise StandardError
    elsif response.is_a?(Hash) && response.has_key?("error")
      raise StandardError
    end
  rescue Net::ReadTimeout, StandardError
    if (retries += 1) <= 5
      sleep 10
      retry
    else
      raise
    end
  end
  return response
end

#uri_for_endpoint(endpoint) ⇒ Object



140
141
142
# File 'lib/reso_api/app/models/reso/api/client.rb', line 140

def uri_for_endpoint endpoint
  return URI(endpoint).host ? URI(endpoint) : URI([base_url, endpoint].join)
end

#validate!Object



17
18
19
20
21
22
# File 'lib/reso_api/app/models/reso/api/client.rb', line 17

def validate!
  raise 'Missing Client ID `client_id`' if client_id.nil?
  raise 'Missing Client Secret `client_secret`' if client_secret.nil?
  raise 'Missing Authentication URL `auth_url`' if auth_url.nil?
  raise 'Missing API Base URL `base_url`' if base_url.nil?
end