-
Notifications
You must be signed in to change notification settings - Fork 3
API Client conventions
Rafael Sales edited this page Aug 27, 2021
·
2 revisions
A client class is one which methods map to actions in the API.
E.g. AirbnbAPI::ReservationClient.new(auth).list
A response class is one that translates low level API attribute names and formatting to the naming and format used in the app.
E.g. 1: The Airbnb reservation response has an attribute named guest_alias_email
, but we store that same attribute as guest_email
in our tables/model, so the response object should respond to reservation_response.guest_email
E.g. 2: The Airbnb reservation response has two attributes: listing.check_in_time
and start_date
, but we use the combination of both with name check_in_at
throughout the app, so the response object should respond to reservation_response.check_in_at
- API Clients should not have any app dependencies - think of an API client as a gem, that shouldn't depend on classes of the app consuming it. E.g. An API client shouldn't make calls to ActiveRecord models or other services.
- Response objects should have method names that match our app naming.
# Base path: app/services
module AirbnbAPI
class Client
include HTTParty
end
# If one client class gets too messy, extract request methods grouped by resource:
class AccountClient < Client
def reservations
response = make_request
response.map { |reservation_data| ReservationResponse.new(reservation_data) }
end
end
# Response objects should provide accessors that wrap the ugliness of the API
class BaseResponse
# Common logic between response objects, if any
attr_reader :data
def initializer(data)
@data = data
end
end
class ReservationResponse < BaseResponse
def starts_at
Time.parse(data.fetch('FuNkY_StArTs_At'))
end
# If you need to save it into an AR as is, the `to_attributes` should map
# the API attributes to the AR attributes.
# If you need to manipulate the to_attributes in order to use when assigning
# to your AR object, it's probably better to just call each instance method
# directly in the caller.
def to_attributes
{
starts_at: starts_at,
...
}
end
end
class WebhookHandler
attr_reader :request, :params
def initialize(request:, params:)
@request = request
@params = params
end
end
end