diff --git a/app/models/exchange_rate.rb b/app/models/exchange_rate.rb index eb17a03a..01b63e2b 100644 --- a/app/models/exchange_rate.rb +++ b/app/models/exchange_rate.rb @@ -15,12 +15,11 @@ class ExchangeRate < ApplicationRecord def find_rates(from:, to:, start_date:, end_date: Date.current, cache: true) rates = self.where(from_currency: from, to_currency: to, date: start_date..end_date).to_a - all_dates = (start_date..end_date).to_a.to_set - existing_dates = rates.map(&:date).to_set + all_dates = (start_date..end_date).to_a + existing_dates = rates.map(&:date) missing_dates = all_dates - existing_dates - if missing_dates.any? - rates += fetch_rates_from_provider(from:, to:, dates: missing_dates, cache:) + rates += fetch_rates_from_provider(from:, to:, start_date: missing_dates.first, end_date: missing_dates.last, cache:) end rates diff --git a/app/models/exchange_rate/provided.rb b/app/models/exchange_rate/provided.rb index a0e0a580..b14bfbdc 100644 --- a/app/models/exchange_rate/provided.rb +++ b/app/models/exchange_rate/provided.rb @@ -6,12 +6,31 @@ module ExchangeRate::Provided class_methods do private - def fetch_rates_from_provider(from:, to:, dates:, cache: false) + def fetch_rates_from_provider(from:, to:, start_date:, end_date: Date.current, cache: false) return [] unless exchange_rates_provider.present? - dates.map do |date| - fetch_rate_from_provider from:, to:, date:, cache: - end.compact + response = exchange_rates_provider.fetch_exchange_rates \ + from: from, + to: to, + start_date: start_date, + end_date: end_date + + if response.success? + response.rates.map do |exchange_rate| + rate = ExchangeRate.new \ + from_currency: from, + to_currency: to, + date: exchange_rate.dig(:date).to_date, + rate: exchange_rate.dig(:rate) + + rate.save! if cache + rate + rescue ActiveRecord::RecordNotUnique + next + end + else + [] + end end def fetch_rate_from_provider(from:, to:, date:, cache: false) diff --git a/app/models/provider/synth.rb b/app/models/provider/synth.rb index d1b6fe26..6a86543e 100644 --- a/app/models/provider/synth.rb +++ b/app/models/provider/synth.rb @@ -57,12 +57,40 @@ class Provider::Synth end end + def fetch_exchange_rates(from:, to:, start_date:, end_date:) + exchange_rates = paginate( + "#{base_url}/rates/historical-range", + from: from, + to: to, + date_start: start_date.to_s, + date_end: end_date.to_s + ) do |body| + body.dig("data").map do |exchange_rate| + { + date: exchange_rate.dig("date"), + rate: exchange_rate.dig("rates", to) + } + end + end + + ExchangeRatesResponse.new \ + rates: exchange_rates, + success?: true, + raw_response: exchange_rates.to_json + rescue StandardError => error + ExchangeRatesResponse.new \ + success?: false, + error: error, + raw_response: error + end + private attr_reader :api_key ExchangeRateResponse = Struct.new :rate, :success?, :error, :raw_response, keyword_init: true SecurityPriceResponse = Struct.new :prices, :success?, :error, :raw_response, keyword_init: true + ExchangeRatesResponse = Struct.new :rates, :success?, :error, :raw_response, keyword_init: true def base_url "https://api.synthfinance.com" diff --git a/test/models/exchange_rate_test.rb b/test/models/exchange_rate_test.rb index 41b0f22b..1a705a5b 100644 --- a/test/models/exchange_rate_test.rb +++ b/test/models/exchange_rate_test.rb @@ -62,8 +62,16 @@ class ExchangeRateTest < ActiveSupport::TestCase end test "finds multiple rates from provider and caches to DB" do - @provider.expects(:fetch_exchange_rate).with(from: "EUR", to: "USD", date: 1.day.ago.to_date).returns(OpenStruct.new(success?: true, rate: 1.1)).once - @provider.expects(:fetch_exchange_rate).with(from: "EUR", to: "USD", date: Date.current).returns(OpenStruct.new(success?: true, rate: 1.2)).once + @provider.expects(:fetch_exchange_rates).with(from: "EUR", to: "USD", start_date: 1.day.ago.to_date, end_date: Date.current) + .returns( + OpenStruct.new( + rates: [ + OpenStruct.new(date: 1.day.ago.to_date, rate: 1.1), + OpenStruct.new(date: Date.current, rate: 1.2) + ], + success?: true + ) + ).once fetched_rates = ExchangeRate.find_rates(from: "EUR", to: "USD", start_date: 1.day.ago.to_date, cache: true) refetched_rates = ExchangeRate.find_rates(from: "EUR", to: "USD", start_date: 1.day.ago.to_date) @@ -73,7 +81,15 @@ class ExchangeRateTest < ActiveSupport::TestCase end test "finds missing db rates from provider and appends to results" do - @provider.expects(:fetch_exchange_rate).with(from: "EUR", to: "GBP", date: 2.days.ago.to_date).returns(OpenStruct.new(success?: true, rate: 1.1)).once + @provider.expects(:fetch_exchange_rates).with(from: "EUR", to: "GBP", start_date: 2.days.ago.to_date, end_date: 2.days.ago.to_date) + .returns( + OpenStruct.new( + rates: [ + OpenStruct.new(date: 2.day.ago.to_date, rate: 1.1) + ], + success?: true + ) + ).once rate1 = exchange_rates(:one) # EUR -> GBP, today rate2 = exchange_rates(:two) # EUR -> GBP, yesterday diff --git a/test/models/provider/synth_test.rb b/test/models/provider/synth_test.rb index 575edf9f..3d0d5b72 100644 --- a/test/models/provider/synth_test.rb +++ b/test/models/provider/synth_test.rb @@ -16,6 +16,17 @@ class Provider::SynthTest < ActiveSupport::TestCase end end + test "fetches paginated exchange_rate historical data" do + VCR.use_cassette("synth/exchange_rate_historical") do + response = @synth.fetch_exchange_rates( + from: "USD", to: "GBP", start_date: Date.parse("01.01.2024"), end_date: Date.parse("31.07.2024") + ) + + assert 213, response.rates.size # 213 days between 01.01.2024 and 31.07.2024 + assert_equal [ :date, :rate ], response.rates.first.keys + end + end + test "retries then provides failed response" do @client = mock Faraday.stubs(:new).returns(@client) diff --git a/test/vcr_cassettes/synth/exchange_rate_historical.yml b/test/vcr_cassettes/synth/exchange_rate_historical.yml new file mode 100644 index 00000000..7e34a6ae --- /dev/null +++ b/test/vcr_cassettes/synth/exchange_rate_historical.yml @@ -0,0 +1,213 @@ +--- +http_interactions: +- request: + method: get + uri: https://api.synthfinance.com/rates/historical-range?date_end=2024-07-31&date_start=2024-01-01&from=USD&page=1&to=GBP + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer + X-Source: + - maybe_app + X-Source-Type: + - managed + User-Agent: + - Faraday v2.10.1 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Aug 2024 17:57:48 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Cf-Ray: + - 8b01640eb8e8451c-TXL + Cf-Cache-Status: + - DYNAMIC + Cache-Control: + - max-age=0, private, must-revalidate + Etag: + - W/"fe9bd64a1b712e0577da8fbfd5bad08d" + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + Rndr-Id: + - d8c1b21e-a6f4-48a0 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Render-Origin-Server: + - Render + X-Request-Id: + - 0003eaec-e246-4769-84f5-7a062eef0908 + X-Runtime: + - '0.040177' + X-Xss-Protection: + - '0' + Server: + - cloudflare + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":[{"date":"2024-01-01","source":"USD","rates":{"GBP":0.785476}},{"date":"2024-01-02","source":"USD","rates":{"GBP":0.785644}},{"date":"2024-01-03","source":"USD","rates":{"GBP":0.792232}},{"date":"2024-01-04","source":"USD","rates":{"GBP":0.789053}},{"date":"2024-01-05","source":"USD","rates":{"GBP":0.788487}},{"date":"2024-01-06","source":"USD","rates":{"GBP":0.785787}},{"date":"2024-01-07","source":"USD","rates":{"GBP":0.785994}},{"date":"2024-01-08","source":"USD","rates":{"GBP":0.786378}},{"date":"2024-01-09","source":"USD","rates":{"GBP":0.784775}},{"date":"2024-01-10","source":"USD","rates":{"GBP":0.786769}},{"date":"2024-01-11","source":"USD","rates":{"GBP":0.784633}},{"date":"2024-01-12","source":"USD","rates":{"GBP":0.782576}},{"date":"2024-01-13","source":"USD","rates":{"GBP":0.78447}},{"date":"2024-01-14","source":"USD","rates":{"GBP":0.784423}},{"date":"2024-01-15","source":"USD","rates":{"GBP":0.785204}},{"date":"2024-01-16","source":"USD","rates":{"GBP":0.786438}},{"date":"2024-01-17","source":"USD","rates":{"GBP":0.791264}},{"date":"2024-01-18","source":"USD","rates":{"GBP":0.788852}},{"date":"2024-01-19","source":"USD","rates":{"GBP":0.786744}},{"date":"2024-01-20","source":"USD","rates":{"GBP":0.787186}},{"date":"2024-01-21","source":"USD","rates":{"GBP":0.787166}},{"date":"2024-01-22","source":"USD","rates":{"GBP":0.787487}},{"date":"2024-01-23","source":"USD","rates":{"GBP":0.786985}},{"date":"2024-01-24","source":"USD","rates":{"GBP":0.787961}},{"date":"2024-01-25","source":"USD","rates":{"GBP":0.786236}},{"date":"2024-01-26","source":"USD","rates":{"GBP":0.786961}},{"date":"2024-01-27","source":"USD","rates":{"GBP":0.786935}},{"date":"2024-01-28","source":"USD","rates":{"GBP":0.787014}},{"date":"2024-01-29","source":"USD","rates":{"GBP":0.78761}},{"date":"2024-01-30","source":"USD","rates":{"GBP":0.786652}},{"date":"2024-01-31","source":"USD","rates":{"GBP":0.787736}},{"date":"2024-02-01","source":"USD","rates":{"GBP":0.788759}},{"date":"2024-02-02","source":"USD","rates":{"GBP":0.784546}},{"date":"2024-02-03","source":"USD","rates":{"GBP":0.791634}},{"date":"2024-02-04","source":"USD","rates":{"GBP":0.791637}},{"date":"2024-02-05","source":"USD","rates":{"GBP":0.792205}},{"date":"2024-02-06","source":"USD","rates":{"GBP":0.797836}},{"date":"2024-02-07","source":"USD","rates":{"GBP":0.79341}},{"date":"2024-02-08","source":"USD","rates":{"GBP":0.791971}},{"date":"2024-02-09","source":"USD","rates":{"GBP":0.792371}},{"date":"2024-02-10","source":"USD","rates":{"GBP":0.791997}},{"date":"2024-02-11","source":"USD","rates":{"GBP":0.792019}},{"date":"2024-02-12","source":"USD","rates":{"GBP":0.791339}},{"date":"2024-02-13","source":"USD","rates":{"GBP":0.791977}},{"date":"2024-02-14","source":"USD","rates":{"GBP":0.794262}},{"date":"2024-02-15","source":"USD","rates":{"GBP":0.795709}},{"date":"2024-02-16","source":"USD","rates":{"GBP":0.793714}},{"date":"2024-02-17","source":"USD","rates":{"GBP":0.793499}},{"date":"2024-02-18","source":"USD","rates":{"GBP":0.79367}},{"date":"2024-02-19","source":"USD","rates":{"GBP":0.792968}},{"date":"2024-02-20","source":"USD","rates":{"GBP":0.794437}},{"date":"2024-02-21","source":"USD","rates":{"GBP":0.791988}},{"date":"2024-02-22","source":"USD","rates":{"GBP":0.791262}},{"date":"2024-02-23","source":"USD","rates":{"GBP":0.789749}},{"date":"2024-02-24","source":"USD","rates":{"GBP":0.78886}},{"date":"2024-02-25","source":"USD","rates":{"GBP":0.789107}},{"date":"2024-02-26","source":"USD","rates":{"GBP":0.78917}},{"date":"2024-02-27","source":"USD","rates":{"GBP":0.788381}},{"date":"2024-02-28","source":"USD","rates":{"GBP":0.78861}},{"date":"2024-02-29","source":"USD","rates":{"GBP":0.789837}},{"date":"2024-03-01","source":"USD","rates":{"GBP":0.792028}},{"date":"2024-03-02","source":"USD","rates":{"GBP":0.790312}},{"date":"2024-03-03","source":"USD","rates":{"GBP":0.790258}},{"date":"2024-03-04","source":"USD","rates":{"GBP":0.789891}},{"date":"2024-03-05","source":"USD","rates":{"GBP":0.788025}},{"date":"2024-03-06","source":"USD","rates":{"GBP":0.787136}},{"date":"2024-03-07","source":"USD","rates":{"GBP":0.785219}},{"date":"2024-03-08","source":"USD","rates":{"GBP":0.780438}},{"date":"2024-03-09","source":"USD","rates":{"GBP":0.777772}},{"date":"2024-03-10","source":"USD","rates":{"GBP":0.777884}},{"date":"2024-03-11","source":"USD","rates":{"GBP":0.77786}},{"date":"2024-03-12","source":"USD","rates":{"GBP":0.780067}},{"date":"2024-03-13","source":"USD","rates":{"GBP":0.781535}},{"date":"2024-03-14","source":"USD","rates":{"GBP":0.781184}},{"date":"2024-03-15","source":"USD","rates":{"GBP":0.784604}},{"date":"2024-03-16","source":"USD","rates":{"GBP":0.785537}},{"date":"2024-03-17","source":"USD","rates":{"GBP":0.785147}},{"date":"2024-03-18","source":"USD","rates":{"GBP":0.785457}},{"date":"2024-03-19","source":"USD","rates":{"GBP":0.785746}},{"date":"2024-03-20","source":"USD","rates":{"GBP":0.786238}},{"date":"2024-03-21","source":"USD","rates":{"GBP":0.781351}},{"date":"2024-03-22","source":"USD","rates":{"GBP":0.789841}},{"date":"2024-03-23","source":"USD","rates":{"GBP":0.793659}},{"date":"2024-03-24","source":"USD","rates":{"GBP":0.793385}},{"date":"2024-03-25","source":"USD","rates":{"GBP":0.793673}},{"date":"2024-03-26","source":"USD","rates":{"GBP":0.791344}},{"date":"2024-03-27","source":"USD","rates":{"GBP":0.791899}},{"date":"2024-03-28","source":"USD","rates":{"GBP":0.792585}},{"date":"2024-03-29","source":"USD","rates":{"GBP":0.792205}},{"date":"2024-03-30","source":"USD","rates":{"GBP":0.792228}},{"date":"2024-03-31","source":"USD","rates":{"GBP":0.792057}},{"date":"2024-04-01","source":"USD","rates":{"GBP":0.79134}},{"date":"2024-04-02","source":"USD","rates":{"GBP":0.797058}},{"date":"2024-04-03","source":"USD","rates":{"GBP":0.795147}},{"date":"2024-04-04","source":"USD","rates":{"GBP":0.790398}},{"date":"2024-04-05","source":"USD","rates":{"GBP":0.791151}},{"date":"2024-04-06","source":"USD","rates":{"GBP":0.791314}},{"date":"2024-04-07","source":"USD","rates":{"GBP":0.791273}},{"date":"2024-04-08","source":"USD","rates":{"GBP":0.792111}},{"date":"2024-04-09","source":"USD","rates":{"GBP":0.790047}}],"paging":{"prev":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=\u0026to=GBP","next":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=2\u0026to=GBP","total_records":213,"current_page":1,"per_page":100,"total_pages":3},"meta":{"credits_used":1,"credits_remaining":53,"date_start":"2024-01-01","date_end":"2024-07-31"}}' + recorded_at: Thu, 08 Aug 2024 17:57:48 GMT +- request: + method: get + uri: https://api.synthfinance.com/rates/historical-range?date_end=2024-07-31&date_start=2024-01-01&from=USD&page=2&to=GBP + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer + X-Source: + - maybe_app + X-Source-Type: + - managed + User-Agent: + - Faraday v2.10.1 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Aug 2024 17:57:48 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Cf-Ray: + - 8b016411c8da2685-TXL + Cf-Cache-Status: + - DYNAMIC + Cache-Control: + - max-age=0, private, must-revalidate + Etag: + - W/"7617d44c8da4ad2ecd071eae8522f17c" + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + Rndr-Id: + - a882d8f9-da35-4532 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Render-Origin-Server: + - Render + X-Request-Id: + - 06a85aa9-8288-484c-80f2-f90ddd97c36e + X-Runtime: + - '0.026746' + X-Xss-Protection: + - '0' + Server: + - cloudflare + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":[{"date":"2024-04-10","source":"USD","rates":{"GBP":0.788828}},{"date":"2024-04-11","source":"USD","rates":{"GBP":0.797646}},{"date":"2024-04-12","source":"USD","rates":{"GBP":0.796524}},{"date":"2024-04-13","source":"USD","rates":{"GBP":0.803024}},{"date":"2024-04-14","source":"USD","rates":{"GBP":0.802912}},{"date":"2024-04-15","source":"USD","rates":{"GBP":0.8025}},{"date":"2024-04-16","source":"USD","rates":{"GBP":0.80344}},{"date":"2024-04-17","source":"USD","rates":{"GBP":0.804505}},{"date":"2024-04-18","source":"USD","rates":{"GBP":0.80301}},{"date":"2024-04-19","source":"USD","rates":{"GBP":0.804145}},{"date":"2024-04-20","source":"USD","rates":{"GBP":0.80845}},{"date":"2024-04-21","source":"USD","rates":{"GBP":0.808199}},{"date":"2024-04-22","source":"USD","rates":{"GBP":0.808004}},{"date":"2024-04-23","source":"USD","rates":{"GBP":0.809734}},{"date":"2024-04-24","source":"USD","rates":{"GBP":0.802955}},{"date":"2024-04-25","source":"USD","rates":{"GBP":0.80264}},{"date":"2024-04-26","source":"USD","rates":{"GBP":0.799526}},{"date":"2024-04-27","source":"USD","rates":{"GBP":0.80053}},{"date":"2024-04-28","source":"USD","rates":{"GBP":0.800761}},{"date":"2024-04-29","source":"USD","rates":{"GBP":0.799397}},{"date":"2024-04-30","source":"USD","rates":{"GBP":0.796217}},{"date":"2024-05-01","source":"USD","rates":{"GBP":0.800703}},{"date":"2024-05-02","source":"USD","rates":{"GBP":0.797562}},{"date":"2024-05-03","source":"USD","rates":{"GBP":0.797457}},{"date":"2024-05-04","source":"USD","rates":{"GBP":0.797001}},{"date":"2024-05-05","source":"USD","rates":{"GBP":0.797107}},{"date":"2024-05-06","source":"USD","rates":{"GBP":0.797363}},{"date":"2024-05-07","source":"USD","rates":{"GBP":0.796218}},{"date":"2024-05-08","source":"USD","rates":{"GBP":0.799915}},{"date":"2024-05-09","source":"USD","rates":{"GBP":0.800422}},{"date":"2024-05-10","source":"USD","rates":{"GBP":0.798411}},{"date":"2024-05-11","source":"USD","rates":{"GBP":0.798489}},{"date":"2024-05-12","source":"USD","rates":{"GBP":0.798475}},{"date":"2024-05-13","source":"USD","rates":{"GBP":0.79853}},{"date":"2024-05-14","source":"USD","rates":{"GBP":0.796122}},{"date":"2024-05-15","source":"USD","rates":{"GBP":0.794614}},{"date":"2024-05-16","source":"USD","rates":{"GBP":0.78804}},{"date":"2024-05-17","source":"USD","rates":{"GBP":0.789188}},{"date":"2024-05-18","source":"USD","rates":{"GBP":0.787162}},{"date":"2024-05-19","source":"USD","rates":{"GBP":0.787194}},{"date":"2024-05-20","source":"USD","rates":{"GBP":0.787022}},{"date":"2024-05-21","source":"USD","rates":{"GBP":0.786793}},{"date":"2024-05-22","source":"USD","rates":{"GBP":0.786723}},{"date":"2024-05-23","source":"USD","rates":{"GBP":0.786132}},{"date":"2024-05-24","source":"USD","rates":{"GBP":0.78778}},{"date":"2024-05-25","source":"USD","rates":{"GBP":0.785013}},{"date":"2024-05-26","source":"USD","rates":{"GBP":0.785081}},{"date":"2024-05-27","source":"USD","rates":{"GBP":0.78526}},{"date":"2024-05-28","source":"USD","rates":{"GBP":0.78296}},{"date":"2024-05-29","source":"USD","rates":{"GBP":0.783808}},{"date":"2024-05-30","source":"USD","rates":{"GBP":0.787552}},{"date":"2024-05-31","source":"USD","rates":{"GBP":0.785599}},{"date":"2024-06-01","source":"USD","rates":{"GBP":0.785113}},{"date":"2024-06-02","source":"USD","rates":{"GBP":0.785019}},{"date":"2024-06-03","source":"USD","rates":{"GBP":0.784657}},{"date":"2024-06-04","source":"USD","rates":{"GBP":0.780649}},{"date":"2024-06-05","source":"USD","rates":{"GBP":0.782934}},{"date":"2024-06-06","source":"USD","rates":{"GBP":0.781631}},{"date":"2024-06-07","source":"USD","rates":{"GBP":0.781732}},{"date":"2024-06-08","source":"USD","rates":{"GBP":0.785947}},{"date":"2024-06-09","source":"USD","rates":{"GBP":0.785767}},{"date":"2024-06-10","source":"USD","rates":{"GBP":0.785588}},{"date":"2024-06-11","source":"USD","rates":{"GBP":0.785791}},{"date":"2024-06-12","source":"USD","rates":{"GBP":0.784932}},{"date":"2024-06-13","source":"USD","rates":{"GBP":0.781472}},{"date":"2024-06-14","source":"USD","rates":{"GBP":0.784041}},{"date":"2024-06-15","source":"USD","rates":{"GBP":0.789096}},{"date":"2024-06-16","source":"USD","rates":{"GBP":0.788449}},{"date":"2024-06-17","source":"USD","rates":{"GBP":0.788479}},{"date":"2024-06-18","source":"USD","rates":{"GBP":0.786542}},{"date":"2024-06-19","source":"USD","rates":{"GBP":0.786916}},{"date":"2024-06-20","source":"USD","rates":{"GBP":0.786107}},{"date":"2024-06-21","source":"USD","rates":{"GBP":0.789875}},{"date":"2024-06-22","source":"USD","rates":{"GBP":0.79058}},{"date":"2024-06-23","source":"USD","rates":{"GBP":0.790546}},{"date":"2024-06-24","source":"USD","rates":{"GBP":0.791248}},{"date":"2024-06-25","source":"USD","rates":{"GBP":0.788496}},{"date":"2024-06-26","source":"USD","rates":{"GBP":0.788395}},{"date":"2024-06-27","source":"USD","rates":{"GBP":0.792298}},{"date":"2024-06-28","source":"USD","rates":{"GBP":0.79087}},{"date":"2024-06-29","source":"USD","rates":{"GBP":0.790726}},{"date":"2024-06-30","source":"USD","rates":{"GBP":0.790719}},{"date":"2024-07-01","source":"USD","rates":{"GBP":0.790622}},{"date":"2024-07-02","source":"USD","rates":{"GBP":0.790812}},{"date":"2024-07-03","source":"USD","rates":{"GBP":0.78816}},{"date":"2024-07-04","source":"USD","rates":{"GBP":0.784451}},{"date":"2024-07-05","source":"USD","rates":{"GBP":0.783992}},{"date":"2024-07-06","source":"USD","rates":{"GBP":0.780243}},{"date":"2024-07-07","source":"USD","rates":{"GBP":0.780594}},{"date":"2024-07-08","source":"USD","rates":{"GBP":0.780827}},{"date":"2024-07-09","source":"USD","rates":{"GBP":0.780333}},{"date":"2024-07-10","source":"USD","rates":{"GBP":0.781936}},{"date":"2024-07-11","source":"USD","rates":{"GBP":0.777992}},{"date":"2024-07-12","source":"USD","rates":{"GBP":0.773816}},{"date":"2024-07-13","source":"USD","rates":{"GBP":0.770374}},{"date":"2024-07-14","source":"USD","rates":{"GBP":0.770294}},{"date":"2024-07-15","source":"USD","rates":{"GBP":0.771174}},{"date":"2024-07-16","source":"USD","rates":{"GBP":0.771041}},{"date":"2024-07-17","source":"USD","rates":{"GBP":0.770574}},{"date":"2024-07-18","source":"USD","rates":{"GBP":0.768775}}],"paging":{"prev":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=1\u0026to=GBP","next":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=3\u0026to=GBP","total_records":213,"current_page":2,"per_page":100,"total_pages":3},"meta":{"credits_used":1,"credits_remaining":52,"date_start":"2024-01-01","date_end":"2024-07-31"}}' + recorded_at: Thu, 08 Aug 2024 17:57:48 GMT +- request: + method: get + uri: https://api.synthfinance.com/rates/historical-range?date_end=2024-07-31&date_start=2024-01-01&from=USD&page=3&to=GBP + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer + X-Source: + - maybe_app + X-Source-Type: + - managed + User-Agent: + - Faraday v2.10.1 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Aug 2024 17:57:49 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Cf-Ray: + - 8b016414b8f758de-TXL + Cf-Cache-Status: + - DYNAMIC + Cache-Control: + - max-age=0, private, must-revalidate + Etag: + - W/"6efe5a0b3e3e58e3c8d2fa5d6525bd61" + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + Vary: + - Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + Rndr-Id: + - bcf6b2fc-a331-4293 + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Render-Origin-Server: + - Render + X-Request-Id: + - 87b3e27e-08bd-4784-8c6f-350622aa08e6 + X-Runtime: + - '0.029529' + X-Xss-Protection: + - '0' + Server: + - cloudflare + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '{"data":[{"date":"2024-07-19","source":"USD","rates":{"GBP":0.772195}},{"date":"2024-07-20","source":"USD","rates":{"GBP":0.774311}},{"date":"2024-07-21","source":"USD","rates":{"GBP":0.774027}},{"date":"2024-07-22","source":"USD","rates":{"GBP":0.773514}},{"date":"2024-07-23","source":"USD","rates":{"GBP":0.77348}},{"date":"2024-07-24","source":"USD","rates":{"GBP":0.775341}},{"date":"2024-07-25","source":"USD","rates":{"GBP":0.775425}},{"date":"2024-07-26","source":"USD","rates":{"GBP":0.777798}},{"date":"2024-07-27","source":"USD","rates":{"GBP":0.777333}},{"date":"2024-07-28","source":"USD","rates":{"GBP":0.77693}},{"date":"2024-07-29","source":"USD","rates":{"GBP":0.77605}},{"date":"2024-07-30","source":"USD","rates":{"GBP":0.77799}},{"date":"2024-07-31","source":"USD","rates":{"GBP":0.778763}}],"paging":{"prev":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=2\u0026to=GBP","next":"/rates/historical-range?date_end=2024-07-31\u0026date_start=2024-01-01\u0026from=USD\u0026page=\u0026to=GBP","total_records":213,"current_page":3,"per_page":100,"total_pages":3},"meta":{"credits_used":1,"credits_remaining":51,"date_start":"2024-01-01","date_end":"2024-07-31"}}' + recorded_at: Thu, 08 Aug 2024 17:57:49 GMT +recorded_with: VCR 6.2.0