Class: AdoptAPet::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/adopt_a_pet/client.rb

Overview

Class for interfacing with the Adopt-A-Pet API

Author:

  • Stephen Dolan

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key = AdoptAPet.api_key) ⇒ void

Create a single instance of a Pet Photo

Examples:

Initialize a new Adopt-A-Pet Client

client = AdoptAPet::Client.new('my_api_key')
pets   = client.pets_at_shelter('12345')

Parameters:

  • api_key (String) (defaults to: AdoptAPet.api_key)

    the API key to authenticate with

Raises:

Author:

  • Stephen Dolan



22
23
24
25
26
27
# File 'lib/adopt_a_pet/client.rb', line 22

def initialize(api_key = AdoptAPet.api_key)
  raise(AdoptAPet::Error, 'API key is required.') unless api_key

  self.api_key = api_key
  self.conn    = setup_connection
end

Instance Attribute Details

#api_keyString

Returns the user’s API key to use in connections.

Returns:

  • (String)

    the user’s API key to use in connections



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/adopt_a_pet/client.rb', line 9

class Client
  attr_accessor :api_key, :conn

  # Create a single instance of a Pet Photo
  # @author Stephen Dolan
  #
  # @param [String] api_key the API key to authenticate with
  #
  # @return [void]
  #
  # @example Initialize a new Adopt-A-Pet Client
  #   client = AdoptAPet::Client.new('my_api_key')
  #   pets   = client.pets_at_shelter('12345')
  def initialize(api_key = AdoptAPet.api_key)
    raise(AdoptAPet::Error, 'API key is required.') unless api_key

    self.api_key = api_key
    self.conn    = setup_connection
  end

  # Retrieves all pets at a shelter
  # @author Stephen Dolan
  #
  # @param [Integer] shelter_id the ID of the shelter to list pets at
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Array<Pet>] a collection of Pets
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pets   = client.pets_at_shelter(12345)
  #   my_pet_name = pets.first.name
  def pets_at_shelter(shelter_id, options = {})
    query = options.merge(shelter_id: shelter_id)
    response = perform_get('/search/pets_at_shelter', query)
    Pet.multiple(response)
  end

  # Retrieves all pets at multiple shelters
  # @author Stephen Dolan
  #
  # @param [Array<Integer>] shelter_ids set of shelter IDs to search for pets at
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Array<Pet>] a collection of Pets
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pets   = client.pets_at_shelter(12345, end_number: 1000)
  #   my_pet_name = pets.first.name
  def pets_at_shelters(shelter_ids, options = {})
    query = options.merge(shelter_id: shelter_ids)
    response = perform_get('/search/pets_at_shelters', query)
    Pet.multiple(response)
  end

  # Retrieves a subset of the total pet data for a single pet
  # @author Stephen Dolan
  #
  # @param [Integer] pet_id the ID of a single pet
  # @param [Hash] opts a placeholder for any options the user would like to submit
  #
  # @return [Pet] a Pet object
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pet    = client.limited_pet_details(123456)
  #   my_pet_special_needs = pet.special_needs
  def limited_pet_details(pet_id, options = {})
    query = options.merge(pet_id: pet_id)
    response = perform_get('/search/limited_pet_details', query)
    Pet.new(response.dig('pet'))
  end

  # Retrieves a complete data set for a single pet
  # @author Stephen Dolan
  #
  # @param [Integer] pet_id the ID of a single pet
  # @param [Hash] opts a placeholder for any options the user would like to submit
  #
  # @return [Pet] a Pet object
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pet    = client.pet_details(123456)
  #   my_pet_housetrained = pet.housetrained
  def pet_details(pet_id, options = {})
    query = options.merge(pet_id: pet_id)
    response = perform_get('/search/pet_details', query)
    Pet.new(response.dig('pet'))
  end

  private

  # Instantiate a Faraday connector with a base URL and adapter
  # @author stephen dolan
  #
  # @return [Faraday::Connection] a faraday object to make requests
  def setup_connection
    # Set up a flexible connection to append the URI to and make requests with
    Faraday.new(url: 'https://api.adoptapet.com') do |faraday|
      # Include to log responses to STDOUT
      # faraday.response :logger

      # Don't encode identical URL paramaeters with []
      faraday.options.params_encoder = Faraday::FlatParamsEncoder

      # Use the default Net::HTTP adapter
      faraday.adapter Faraday.default_adapter
    end
  end

  # Helper method to fetch data from the Adopt-A-Pet API endpoint
  # @author Stephen Dolan
  #
  # @param [String] the URI to make the GET request to
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Hash] an Adopt-A-Pet JSON API response parsed to a Ruby Hash
  def perform_get(uri, options = {})
    # Always fetch the output in JSON format
    options = options.merge(output: :json)

    # Always include the API key
    options = options.merge(key: api_key)

    # Always set the API version to version 1
    options = options.merge(v: 1)

    # Make the request
    response = conn.get(uri, options)

    # Validate the body and transform into a Ruby object
    process_json_response(response.body)
  end

  # Parses a JSON body into a Ruby object if it is a valid response
  # @author Stephen Dolan
  #
  # @param [String] the JSON response body from an Adopt-A-Pet API request
  #
  # @return [Hash] an Adopt-A-Pet JSON API response parsed to a Ruby Hash
  def process_json_response(response_body)
    # Parse the response into a Ruby object
    response_object = JSON.parse(response_body)

    # Return the Ruby object if the response was valid
    return response_object if valid_json_response(response_object)
  end

  # Ensure that the JSON HTTP response received is valid
  # @author Stephen Dolan
  #
  # @param [Hash] a Ruby hash representing an Adopt-A-Pet API response
  #
  # @raise [Exception] if the response is not valid, throw an exception
  #
  # @return [true] always return true if the method completes
  def valid_json_response(response_object)
    # Grab the status from the response
    response_status = response_object.dig('status')

    # If we receive a status 'ok', make sure there are no exceptions
    # If we receive a status 'fail', raise an exception
    # If we receive anything else, raise an exception
    if response_status == 'ok'
      check_ok_response(response_object)
    elsif response_status == 'fail'
      puts response_object
      raise 'Bad request. Response returned status "fail".'
    else
      raise 'Bad request. Invalid response status returned.'
    end

    # Return true if all validations pass
    true
  end

  # Verify that there was no issue with an 'ok' response
  # @author Stephen Dolan
  #
  # @param [Hash] a Ruby hash representing an Adopt-A-Pet API response
  #
  # @raise [Exception] if the response is not valid, throw an exception
  #
  # @return [true] always return true if there is no exception
  def check_ok_response(response_object)
    return true unless response_object.key? 'exception'

    exception_message = response_object.dig('exception', 'details')
    raise "Bad request. Exception occurred: #{exception_message}"
  end
end

#connFaraday::Connection

Returns a Faraday object to make requests.

Returns:

  • (Faraday::Connection)

    a Faraday object to make requests



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/adopt_a_pet/client.rb', line 9

class Client
  attr_accessor :api_key, :conn

  # Create a single instance of a Pet Photo
  # @author Stephen Dolan
  #
  # @param [String] api_key the API key to authenticate with
  #
  # @return [void]
  #
  # @example Initialize a new Adopt-A-Pet Client
  #   client = AdoptAPet::Client.new('my_api_key')
  #   pets   = client.pets_at_shelter('12345')
  def initialize(api_key = AdoptAPet.api_key)
    raise(AdoptAPet::Error, 'API key is required.') unless api_key

    self.api_key = api_key
    self.conn    = setup_connection
  end

  # Retrieves all pets at a shelter
  # @author Stephen Dolan
  #
  # @param [Integer] shelter_id the ID of the shelter to list pets at
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Array<Pet>] a collection of Pets
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pets   = client.pets_at_shelter(12345)
  #   my_pet_name = pets.first.name
  def pets_at_shelter(shelter_id, options = {})
    query = options.merge(shelter_id: shelter_id)
    response = perform_get('/search/pets_at_shelter', query)
    Pet.multiple(response)
  end

  # Retrieves all pets at multiple shelters
  # @author Stephen Dolan
  #
  # @param [Array<Integer>] shelter_ids set of shelter IDs to search for pets at
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Array<Pet>] a collection of Pets
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pets   = client.pets_at_shelter(12345, end_number: 1000)
  #   my_pet_name = pets.first.name
  def pets_at_shelters(shelter_ids, options = {})
    query = options.merge(shelter_id: shelter_ids)
    response = perform_get('/search/pets_at_shelters', query)
    Pet.multiple(response)
  end

  # Retrieves a subset of the total pet data for a single pet
  # @author Stephen Dolan
  #
  # @param [Integer] pet_id the ID of a single pet
  # @param [Hash] opts a placeholder for any options the user would like to submit
  #
  # @return [Pet] a Pet object
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pet    = client.limited_pet_details(123456)
  #   my_pet_special_needs = pet.special_needs
  def limited_pet_details(pet_id, options = {})
    query = options.merge(pet_id: pet_id)
    response = perform_get('/search/limited_pet_details', query)
    Pet.new(response.dig('pet'))
  end

  # Retrieves a complete data set for a single pet
  # @author Stephen Dolan
  #
  # @param [Integer] pet_id the ID of a single pet
  # @param [Hash] opts a placeholder for any options the user would like to submit
  #
  # @return [Pet] a Pet object
  #
  # @example
  #   client = AdoptAPet::Client.new('my_key')
  #   pet    = client.pet_details(123456)
  #   my_pet_housetrained = pet.housetrained
  def pet_details(pet_id, options = {})
    query = options.merge(pet_id: pet_id)
    response = perform_get('/search/pet_details', query)
    Pet.new(response.dig('pet'))
  end

  private

  # Instantiate a Faraday connector with a base URL and adapter
  # @author stephen dolan
  #
  # @return [Faraday::Connection] a faraday object to make requests
  def setup_connection
    # Set up a flexible connection to append the URI to and make requests with
    Faraday.new(url: 'https://api.adoptapet.com') do |faraday|
      # Include to log responses to STDOUT
      # faraday.response :logger

      # Don't encode identical URL paramaeters with []
      faraday.options.params_encoder = Faraday::FlatParamsEncoder

      # Use the default Net::HTTP adapter
      faraday.adapter Faraday.default_adapter
    end
  end

  # Helper method to fetch data from the Adopt-A-Pet API endpoint
  # @author Stephen Dolan
  #
  # @param [String] the URI to make the GET request to
  # @param [Hash] opts the options to include with the request
  # @option opts [String] :start_number (1) where to start results
  # @option opts [String] :end_number (50) where to end results
  #
  # @return [Hash] an Adopt-A-Pet JSON API response parsed to a Ruby Hash
  def perform_get(uri, options = {})
    # Always fetch the output in JSON format
    options = options.merge(output: :json)

    # Always include the API key
    options = options.merge(key: api_key)

    # Always set the API version to version 1
    options = options.merge(v: 1)

    # Make the request
    response = conn.get(uri, options)

    # Validate the body and transform into a Ruby object
    process_json_response(response.body)
  end

  # Parses a JSON body into a Ruby object if it is a valid response
  # @author Stephen Dolan
  #
  # @param [String] the JSON response body from an Adopt-A-Pet API request
  #
  # @return [Hash] an Adopt-A-Pet JSON API response parsed to a Ruby Hash
  def process_json_response(response_body)
    # Parse the response into a Ruby object
    response_object = JSON.parse(response_body)

    # Return the Ruby object if the response was valid
    return response_object if valid_json_response(response_object)
  end

  # Ensure that the JSON HTTP response received is valid
  # @author Stephen Dolan
  #
  # @param [Hash] a Ruby hash representing an Adopt-A-Pet API response
  #
  # @raise [Exception] if the response is not valid, throw an exception
  #
  # @return [true] always return true if the method completes
  def valid_json_response(response_object)
    # Grab the status from the response
    response_status = response_object.dig('status')

    # If we receive a status 'ok', make sure there are no exceptions
    # If we receive a status 'fail', raise an exception
    # If we receive anything else, raise an exception
    if response_status == 'ok'
      check_ok_response(response_object)
    elsif response_status == 'fail'
      puts response_object
      raise 'Bad request. Response returned status "fail".'
    else
      raise 'Bad request. Invalid response status returned.'
    end

    # Return true if all validations pass
    true
  end

  # Verify that there was no issue with an 'ok' response
  # @author Stephen Dolan
  #
  # @param [Hash] a Ruby hash representing an Adopt-A-Pet API response
  #
  # @raise [Exception] if the response is not valid, throw an exception
  #
  # @return [true] always return true if there is no exception
  def check_ok_response(response_object)
    return true unless response_object.key? 'exception'

    exception_message = response_object.dig('exception', 'details')
    raise "Bad request. Exception occurred: #{exception_message}"
  end
end

Instance Method Details

#limited_pet_details(pet_id, options = {}) ⇒ Pet

Retrieves a subset of the total pet data for a single pet

Examples:

client = AdoptAPet::Client.new('my_key')
pet    = client.limited_pet_details(123456)
my_pet_special_needs = pet.special_needs

Parameters:

  • pet_id (Integer)

    the ID of a single pet

  • opts (Hash)

    a placeholder for any options the user would like to submit

Returns:

  • (Pet)

    a Pet object

Author:

  • Stephen Dolan



81
82
83
84
85
# File 'lib/adopt_a_pet/client.rb', line 81

def limited_pet_details(pet_id, options = {})
  query = options.merge(pet_id: pet_id)
  response = perform_get('/search/limited_pet_details', query)
  Pet.new(response.dig('pet'))
end

#pet_details(pet_id, options = {}) ⇒ Pet

Retrieves a complete data set for a single pet

Examples:

client = AdoptAPet::Client.new('my_key')
pet    = client.pet_details(123456)
my_pet_housetrained = pet.housetrained

Parameters:

  • pet_id (Integer)

    the ID of a single pet

  • opts (Hash)

    a placeholder for any options the user would like to submit

Returns:

  • (Pet)

    a Pet object

Author:

  • Stephen Dolan



99
100
101
102
103
# File 'lib/adopt_a_pet/client.rb', line 99

def pet_details(pet_id, options = {})
  query = options.merge(pet_id: pet_id)
  response = perform_get('/search/pet_details', query)
  Pet.new(response.dig('pet'))
end

#pets_at_shelter(shelter_id, options = {}) ⇒ Array<Pet>

Retrieves all pets at a shelter

Examples:

client = AdoptAPet::Client.new('my_key')
pets   = client.pets_at_shelter(12345)
my_pet_name = pets.first.name

Parameters:

  • shelter_id (Integer)

    the ID of the shelter to list pets at

  • opts (Hash)

    the options to include with the request

Returns:

  • (Array<Pet>)

    a collection of Pets

Author:

  • Stephen Dolan



43
44
45
46
47
# File 'lib/adopt_a_pet/client.rb', line 43

def pets_at_shelter(shelter_id, options = {})
  query = options.merge(shelter_id: shelter_id)
  response = perform_get('/search/pets_at_shelter', query)
  Pet.multiple(response)
end

#pets_at_shelters(shelter_ids, options = {}) ⇒ Array<Pet>

Retrieves all pets at multiple shelters

Examples:

client = AdoptAPet::Client.new('my_key')
pets   = client.pets_at_shelter(12345, end_number: 1000)
my_pet_name = pets.first.name

Parameters:

  • shelter_ids (Array<Integer>)

    set of shelter IDs to search for pets at

  • opts (Hash)

    the options to include with the request

Returns:

  • (Array<Pet>)

    a collection of Pets

Author:

  • Stephen Dolan



63
64
65
66
67
# File 'lib/adopt_a_pet/client.rb', line 63

def pets_at_shelters(shelter_ids, options = {})
  query = options.merge(shelter_id: shelter_ids)
  response = perform_get('/search/pets_at_shelters', query)
  Pet.multiple(response)
end