API Service in Rails

Most of the time I say fuck it and don’t wrap my api calls in a service. However, it’s worthwhile? Some people say it’s worthwhile.

JEFF JUST REMINDED ME IT IS WORTHWHILE BECAUSE THEN YOU CAN USE THE SERVICE ALL THROUGHOUT YOUR APPLICATION. THEN, IF THE API CHANGES, YOU ONLY NEED TO CHANGE YOUR CODE IN ONE SPOT. PRETTY SMART.

https://robots.thoughtbot.com/how-to-stub-external-services-in-tests Testing external services

# lib/services/loantek_service.rb
class Services::LoantekService
  UnhandledResponseError = Class.new(StandardError)

  cattr_accessor :base_url_endpoint

  self.base_url_endpoint = ENV.fetch("loantek_endpoint")

  def self.fetch
  new.fetch
  end

  def initialize
  end

  def fetch
  response = HTTParty.post(
      self.class.base_url_endpoint,
      body: post_parameters.to_json,
      headers: { 'Content-Type' => 'application/json' }
      )

  case response.code

  when 422
    InvalidQuote.new
  when 200..299
    fifteen_year = response["Quotes"].select { |quote| quote["ProductName"] == "15yearFixed" }
    thirty_year = response["Quotes"].select { |quote| quote["ProductName"] == "30yearFixed" }
    Rate.create(rate: fifteen_year[0]["Rate"], apr: fifteen_year[0]["APR"], product:fifteen_year[0]["ProductName"], total_fees: fifteen_year[0]["QuoteFees"], discount_points: fifteen_year[0]["DiscountPts"])
    Rate.create(rate: thirty_year[0]["Rate"], apr: thirty_year[0]["APR"], product:thirty_year[0]["ProductName"], total_fees: thirty_year[0]["QuoteFees"], discount_points: thirty_year[0]["DiscountPts"])
  else
    raise UnhandledResponseError
  end
end

private

def post_parameters
  {"PropertyUsage":"PrimaryResidence","PropertyType":"SingleFamily","LoanProgramsOfInterest":["ThirtyYearFixed","FifteenYearFixed"],"LockPeriod":"60","DebtToIncomeRatio":"","QuoteTypesToReturn":["ClosestTo01"],"VAType":"NotApplicable","CombinedLoanToValue":""}
end
end

Utilize the service

class Rate < ApplicationRecord
  scope :todays_15_year, -> { where(product:"15yearFixed").last }
  scope :todays_30_year, -> { where(product:"30yearFixed").last }

  class << self
    def save_rates
      Services::LoantekService.fetch
    end
  end
end

Make the service available within your application

# config/application.rb
# load lib
config.autoload_paths << Rails.root.join('lib')

Post Content