class BookingSync::API::Client

Constants

MEDIA_TYPE

Attributes

last_response[R]
logger[R]
pagination_first_response[R]
token[R]

Public Class Methods

new(token, options = {}) { |conn| ... } click to toggle source

Initialize new Client

@param token [String] OAuth token @param options [Hash] @option options [String] base_url: Base URL to BookingSync site @option options [Logger] logger: Logger where headers and body of every

request and response will be logged.

@option options [Module] instrumenter: A module that responds to

instrument, usually ActiveSupport::Notifications.

@return [BookingSync::API::Client] New BookingSync API client

# File lib/bookingsync/api/client.rb, line 130
def initialize(token, options = {})
  @token = token
  @logger = options[:logger] || default_logger
  @instrumenter = options[:instrumenter] || NoopInstrumenter
  @base_url = options[:base_url]
  @serializer = Serializer.new
  @conn = build_connection
  @conn.headers[:accept] = MEDIA_TYPE
  @conn.headers[:content_type] = MEDIA_TYPE
  @conn.headers[:user_agent] = user_agent
  @conn.url_prefix = api_endpoint
  yield @conn if block_given?
end

Public Instance Methods

api_endpoint() click to toggle source

Return API endpoint

@return [String] URL to API endpoint

# File lib/bookingsync/api/client.rb, line 192
def api_endpoint
  URI.join(base_url, "api/v3").to_s
end
call(method, path, data = nil, options = nil) click to toggle source

Make a HTTP request to given path and returns Response object.

@param method [Symbol] HTTP verb to use. @param path [String] The path, relative to {#api_endpoint}. @param data [Hash] Data to be send in the request’s body

it can include query: key with requests params for GET requests

@param options [Hash] A customizable set of request options. @return [BookingSync::API::Response] A Response object.

# File lib/bookingsync/api/client.rb, line 262
def call(method, path, data = nil, options = nil)
  instrument("call.bookingsync_api", method: method, path: path) do
    if [:get, :head].include?(method)
      options = data
      data = {}
    end
    options ||= {}
    options[:headers] ||= {}
    options[:headers]["Authorization"] = "Bearer #{token}"

    if options.has_key?(:query)
      if options[:query].has_key?(:ids)
        ids = Array(options[:query].delete(:ids)).join(",")
        path = "#{path}/#{ids}"
      end
      options[:query].keys.each do |key|
        if options[:query][key].is_a?(Array)
          options[:query][key] = options[:query][key].join(",")
        end
      end
    end

    url = expand_url(path, options[:uri])
    res = @conn.send(method, url) do |req|
      if data
        req.body = data.is_a?(String) ? data : encode_body(data)
      end
      if params = options[:query]
        req.params.update params
      end
      req.headers.update options[:headers]
    end
    handle_response(res)
  end
end
decode_body(str) click to toggle source

Decode a String response body to a Resource.

@param str [String] The String body from the response. @return [Object] Object resource

# File lib/bookingsync/api/client.rb, line 208
def decode_body(str)
  @serializer.decode(str)
end
delete(path, options = {}) click to toggle source

Make a HTTP DELETE request

@param path [String] The path, relative to {#api_endpoint} @param options [Hash] Body params for the request @return [Array<BookingSync::API::Resource>]

# File lib/bookingsync/api/client.rb, line 185
def delete(path, options = {})
  request :delete, path, options
end
encode_body(data) click to toggle source

Encode an object to a string for the API request.

@param data [Object] The Hash or Resource that is being sent. @return [String] Object encoded into JSON string

# File lib/bookingsync/api/client.rb, line 200
def encode_body(data)
  @serializer.encode(data)
end
get(path, options = {}) click to toggle source

Make a HTTP GET request

@param path [String] The path, relative to {#api_endpoint} @param options [Hash] Query params for the request @return [Array<BookingSync::API::Resource>] Array of resources.

# File lib/bookingsync/api/client.rb, line 149
def get(path, options = {})
  request :get, path, query: options
end
paginate(path, options = {}, &block) click to toggle source

Make a HTTP GET or POST request to a path with pagination support.

@param options [Hash] @option options [Integer] per_page: Number of resources per page @option options [Integer] page: Number of page to return @option options [Boolean] auto_paginate: If true, all resources will

be returned. It makes multiple requestes underneath and joins the results.

@yieldreturn [Array<BookingSync::API::Resource>] Batch of resources @return [Array<BookingSync::API::Resource>] Batch of resources

# File lib/bookingsync/api/client.rb, line 237
def paginate(path, options = {}, &block)
  instrument("paginate.bookingsync_api", path: path) do
    request_settings = {
      auto_paginate: options.delete(:auto_paginate),
      request_method: options.delete(:request_method) || :get
    }

    if block_given?
      data = fetch_with_block(path, options, request_settings, &block)
    else
      data = fetch_with_paginate(path, options, request_settings)
    end

    data
  end
end
patch(path, options = {}) click to toggle source

Make a HTTP PATCH request

@param path [String] The path, relative to {#api_endpoint} @param options [Hash] Body params for the request @return [Array<BookingSync::API::Resource>]

# File lib/bookingsync/api/client.rb, line 176
def patch(path, options = {})
  request :patch, path, options
end
post(path, options = {}) click to toggle source

Make a HTTP POST request

@param path [String] The path, relative to {#api_endpoint} @param options [Hash] Body params for the request @return [Array<BookingSync::API::Resource>]

# File lib/bookingsync/api/client.rb, line 158
def post(path, options = {})
  request :post, path, options
end
put(path, options = {}) click to toggle source

Make a HTTP PUT request

@param path [String] The path, relative to {#api_endpoint} @param options [Hash] Body params for the request @return [Array<BookingSync::API::Resource>]

# File lib/bookingsync/api/client.rb, line 167
def put(path, options = {})
  request :put, path, options
end
request(method, path, data = nil, options = nil) click to toggle source

Make a HTTP request to a path and returns an Array of Resources

@param method [Symbol] HTTP verb to use. @param path [String] The path, relative to {#api_endpoint}. @param data [Hash] Data to be send in the request’s body

it can include query: key with requests params for GET requests

@param options [Hash] A customizable set of request options. @return [Array<BookingSync::API::Resource>] Array of resources.

# File lib/bookingsync/api/client.rb, line 220
def request(method, path, data = nil, options = nil)
  instrument("request.bookingsync_api", method: method, path: path) do
    response = call(method, path, data, options)
    response.respond_to?(:resources) ? response.resources : response
  end
end
with_headers(extra_headers = {}) { |self| ... } click to toggle source

Yields client with temporarily modified headers.

@param extra_headers [Hash] Additional headers added to next request. @yieldreturn [BookingSync::API::Client] Client with modified default headers. @return [Array<BookingSync::API::Resource>|BookingSync::API::Resource|String|Object] Client response

# File lib/bookingsync/api/client.rb, line 303
def with_headers(extra_headers = {}, &block)
  original_headers = @conn.headers.dup
  @conn.headers.merge!(extra_headers)
  result = yield self
  @conn.headers = original_headers
  result
end

Private Instance Methods

base_url() click to toggle source

Return BookingSync base URL. Default is www.bookingsync.com it can be altered via ENV variable BOOKINGSYNC_URL which is useful in specs when recording vcr cassettes. In also can be passed as :base_url option when initializing the Client object

@return [String] Base URL to BookingSync

# File lib/bookingsync/api/client.rb, line 330
def base_url
  @base_url || ENV.fetch("BOOKINGSYNC_URL", "https://www.bookingsync.com")
end
build_connection() click to toggle source
# File lib/bookingsync/api/client.rb, line 313
def build_connection
  Faraday.new(**faraday_options) do |f|
    f.use :logger, logger
    f.adapter :net_http_persistent
  end
end
debug?() click to toggle source
# File lib/bookingsync/api/client.rb, line 374
def debug?
  ENV["BOOKINGSYNC_API_DEBUG"] == "true"
end
default_logger() click to toggle source

Return default logger. By default we don’t log anywhere. If we are in debug mode, we log everything to STDOUT.

@return [Logger] Logger where faraday middleware will log requests and

responses.
# File lib/bookingsync/api/client.rb, line 383
def default_logger
  Logger.new(debug? ? STDOUT : nil)
end
expand_url(url, options = nil) click to toggle source

Expand an URL template into a full URL

@param url [String|Addressable::Template] - An URL to be expanded @param options [Hash] - Variables which will be used to expand @return [String] - Expanded URL

# File lib/bookingsync/api/client.rb, line 349
def expand_url(url, options = nil)
  tpl = url.respond_to?(:expand) ? url : ::Addressable::Template.new(url.to_s)
  tpl.expand(options || {}).to_s
end
faraday_options() click to toggle source
# File lib/bookingsync/api/client.rb, line 320
def faraday_options
  { ssl: { verify: verify_ssl? } }
end
fetch_with_block(path, options, request_settings, response = nil, &block) click to toggle source
# File lib/bookingsync/api/client.rb, line 409
def fetch_with_block(path, options, request_settings, response = nil, &block)
  response = initial_call(path, options, request_settings) unless response
  block.call(response.resources)
  if response.relations[:next]
    fetch_with_block(path, options, request_settings, next_page(response, request_settings), &block)
  end
end
fetch_with_paginate(path, options, request_settings, data = [], response = nil) click to toggle source
# File lib/bookingsync/api/client.rb, line 399
def fetch_with_paginate(path, options, request_settings, data = [], response = nil)
  response = initial_call(path, options, request_settings) unless response
  data.concat(response.resources)
  if response.relations[:next] && request_settings[:auto_paginate]
    fetch_with_paginate(path, options, request_settings, data, next_page(response, request_settings))
  else
    data
  end
end
handle_response(faraday_response) click to toggle source

Process faraday response.

@param faraday_response [Faraday::Response] - A response to process @raise [BookingSync::API::Unauthorized] - On unauthorized user @raise [BookingSync::API::UnprocessableEntity] - On validations error @return [BookingSync::API::Response|NilClass]

# File lib/bookingsync/api/client.rb, line 360
def handle_response(faraday_response)
  @last_response = response = Response.new(self, faraday_response)
  case response.status
  when 204; nil # destroy/cancel
  when 200..299; response
  when 401; raise Unauthorized.new(response)
  when 403; raise Forbidden.new(response)
  when 404; raise NotFound.new(response)
  when 422; raise UnprocessableEntity.new(response)
  when 429; raise RateLimitExceeded.new(response)
  else raise UnsupportedResponse.new(response)
  end
end
initial_call(path, options, request_settings) click to toggle source
# File lib/bookingsync/api/client.rb, line 417
def initial_call(path, options, request_settings)
  request_method = request_settings[:request_method]
  if request_method == :get
    response = call(request_method, path, query: options)
  else
    response = call(request_method, path, options)
  end
  @pagination_first_response = response
end
next_page(response, request_settings) click to toggle source
# File lib/bookingsync/api/client.rb, line 427
def next_page(response, request_settings)
  response.relations[:next].call({}, { method: request_settings[:request_method] })
end
reject_blank_values(array) click to toggle source
# File lib/bookingsync/api/client.rb, line 431
def reject_blank_values(array)
  array.reject { |value| value.nil? || value == "" }
end
user_agent() click to toggle source

Return user agent with gem version, can be logged in API.

# File lib/bookingsync/api/client.rb, line 388
def user_agent
  "BookingSync API gem v#{BookingSync::API::VERSION}"
end
verify_ssl?() click to toggle source

Return true if SSL cert should be verified By default is true, can be changed to false using env variable VERIFY_SSL

@return [Boolean] true if SSL needs to be verified false otherwise

# File lib/bookingsync/api/client.rb, line 340
def verify_ssl?
  ENV["BOOKINGSYNC_VERIFY_SSL"] != "false"
end