diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4695914..fa62e47 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,7 @@ updates: directory: "/" schedule: interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index afd057d..b9f5586 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -51,7 +51,7 @@ jobs: COVERAGE: true run: bundle exec rspec - name: Upload coverage results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: coverage-report path: coverage @@ -103,10 +103,11 @@ jobs: fail-fast: false matrix: ruby: - - ruby-2.6 - ruby-2.7 - ruby-3.0 - ruby-3.1 + - ruby-3.2 + - ruby-3.3 steps: - uses: actions/checkout@v3 diff --git a/.rubocop.yml b/.rubocop.yml index cf6b6a8..9224163 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,8 +2,9 @@ require: rubocop-rake inherit_gem: gc_ruboconfig: rubocop.yml + AllCops: - TargetRubyVersion: 2.6 + TargetRubyVersion: 2.7 NewCops: enable RSpec/ExampleLength: diff --git a/Gemfile b/Gemfile index de28229..4761055 100644 --- a/Gemfile +++ b/Gemfile @@ -6,13 +6,14 @@ source "https://rubygems.org" gemspec group :development, :test do - gem "gc_ruboconfig", "~> 3.6.0" + gem "appraisal", "~> 2.4" + gem "gc_ruboconfig", "~> 5.0.1" gem "pry", "~> 0.14.1" gem "rake", "~> 13.0" gem "rspec", "~> 3.12.0" gem "rspec-its", "~> 1.3.0" gem "rspec_junit_formatter", "~> 0.6.0" - gem "rubocop", "~> 1.50.0" + gem "rubocop", "~> 1.65.0" gem "rubocop-rake", "~> 0.6.0" gem "simplecov", "~> 0.22.0" gem "webmock", "~> 3.18.1" diff --git a/duffel_api.gemspec b/duffel_api.gemspec index 5e34d6b..41ee031 100644 --- a/duffel_api.gemspec +++ b/duffel_api.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| spec.summary = "A Ruby client for interacting with the Duffel API" spec.homepage = "https://github.com/duffelhq/duffel-api-ruby" spec.license = "MIT" - spec.required_ruby_version = ">= 2.6.0" + spec.required_ruby_version = ">= 2.7.0" spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage @@ -32,8 +32,6 @@ Gem::Specification.new do |spec| spec.add_dependency "base16", "~> 0.0.2" spec.add_dependency "faraday", ">= 0.9.2", "< 3" - spec.add_development_dependency "appraisal", "~> 2.4" - # For more information and examples about making a new gem, checkout our # guide at: https://bundler.io/guides/creating_gem.html spec.metadata = { diff --git a/examples/book_and_change.rb b/examples/book_and_change.rb index 45c5bf4..2386664 100644 --- a/examples/book_and_change.rb +++ b/examples/book_and_change.rb @@ -9,10 +9,15 @@ # 365 days from now departure_date = (Time.now + (60 * 60 * 24 * 365)).strftime("%Y-%m-%d") +birth_date = Date.parse("1993-04-01") +current_date = Date.today +age = current_date.year - birth_date.year +age += 1 if current_date.yday > birth_date.yday + offer_request = client.offer_requests.create(params: { cabin_class: "economy", passengers: [{ - age: 28, + age: age, }], slices: [{ # We use a non-sensical route to make sure we get speedy, reliable Duffel Airways @@ -57,7 +62,7 @@ gender: "m", given_name: "Tim", family_name: "Rogers", - born_on: "1993-04-01", + born_on: birth_date.to_s, phone_number: "+441290211999", email: "tim@duffel.com", }, @@ -71,7 +76,7 @@ slices: { add: [{ cabin_class: "economy", - departure_date: "2022-12-25", + departure_date: (current_date + 90).to_s, origin: "LHR", destination: "STN", }], diff --git a/examples/book_with_extra_baggage.rb b/examples/book_with_extra_baggage.rb index 0325dbd..002d78a 100644 --- a/examples/book_with_extra_baggage.rb +++ b/examples/book_with_extra_baggage.rb @@ -10,10 +10,15 @@ # 365 days from now departure_date = (Time.now + (60 * 60 * 24 * 365)).strftime("%Y-%m-%d") +birth_date = Date.parse("1993-04-01") +current_date = Date.today +age = current_date.year - birth_date.year +age += 1 if current_date.yday > birth_date.yday + offer_request = client.offer_requests.create(params: { cabin_class: "economy", passengers: [{ - age: 28, + age: age, }], slices: [{ # We use a non-sensical route to make sure we get speedy, reliable Duffel Airways @@ -75,7 +80,7 @@ gender: "m", given_name: "Tim", family_name: "Rogers", - born_on: "1993-04-01", + born_on: birth_date.to_s, phone_number: "+441290211999", email: "tim@duffel.com", }, diff --git a/examples/book_with_seat.rb b/examples/book_with_seat.rb index f7569b4..96abc05 100644 --- a/examples/book_with_seat.rb +++ b/examples/book_with_seat.rb @@ -10,10 +10,15 @@ # 365 days from now departure_date = (Time.now + (60 * 60 * 24 * 365)).strftime("%Y-%m-%d") +birth_date = Date.parse("1993-04-01") +current_date = Date.today +age = current_date.year - birth_date.year +age += 1 if current_date.yday > birth_date.yday + offer_request = client.offer_requests.create(params: { cabin_class: "economy", passengers: [{ - age: 28, + age: age, }], slices: [{ # We use a non-sensical route to make sure we get speedy, reliable Duffel Airways @@ -83,7 +88,7 @@ gender: "m", given_name: "Tim", family_name: "Rogers", - born_on: "1993-04-01", + born_on: birth_date.to_s, phone_number: "+441290211999", email: "tim@duffel.com", }, diff --git a/examples/hold_and_pay_later.rb b/examples/hold_and_pay_later.rb index d45b624..55ce2ad 100644 --- a/examples/hold_and_pay_later.rb +++ b/examples/hold_and_pay_later.rb @@ -9,10 +9,15 @@ # 365 days from now departure_date = (Time.now + (60 * 60 * 24 * 365)).strftime("%Y-%m-%d") +birth_date = Date.parse("1993-04-01") +current_date = Date.today +age = current_date.year - birth_date.year +age += 1 if current_date.yday > birth_date.yday + offer_request = client.offer_requests.create(params: { cabin_class: "economy", passengers: [{ - age: 28, + age: age, }], slices: [{ # We use a non-sensical route to make sure we get speedy, reliable Duffel Airways @@ -52,7 +57,7 @@ gender: "m", given_name: "Tim", family_name: "Rogers", - born_on: "1993-04-01", + born_on: birth_date.to_s, phone_number: "+441290211999", email: "tim@duffel.com", }, diff --git a/examples/search_and_book.rb b/examples/search_and_book.rb index add28bd..b6dc1f2 100644 --- a/examples/search_and_book.rb +++ b/examples/search_and_book.rb @@ -10,10 +10,15 @@ # 365 days from now departure_date = (Time.now + (60 * 60 * 24 * 365)).strftime("%Y-%m-%d") +birth_date = Date.parse("1993-04-01") +current_date = Date.today +age = current_date.year - birth_date.year +age += 1 if current_date.yday > birth_date.yday + offer_request = client.offer_requests.create(params: { cabin_class: "economy", passengers: [{ - age: 28, + age: age, }], slices: [{ # We use a non-sensical route to make sure we get speedy, reliable Duffel Airways @@ -72,7 +77,7 @@ gender: "m", given_name: "Tim", family_name: "Rogers", - born_on: "1993-04-01", + born_on: birth_date.to_s, phone_number: "+441290211999", email: "tim@duffel.com", }, diff --git a/gemfiles/faraday_1.gemfile b/gemfiles/faraday_1.gemfile index 0234a18..fb103af 100644 --- a/gemfiles/faraday_1.gemfile +++ b/gemfiles/faraday_1.gemfile @@ -7,16 +7,17 @@ source "https://rubygems.org" gem "faraday", "1.8.0" group :development, :test do - gem "gc_ruboconfig", "~> 2.32.0" + gem "appraisal", "~> 2.4" + gem "gc_ruboconfig", "~> 5.0.1" gem "pry", "~> 0.14.1" gem "rake", "~> 13.0" - gem "rspec", "~> 3.11.0" + gem "rspec", "~> 3.12.0" gem "rspec-its", "~> 1.3.0" - gem "rspec_junit_formatter", "~> 0.5.0" - gem "rubocop", "~> 1.25.0" + gem "rspec_junit_formatter", "~> 0.6.0" + gem "rubocop", "~> 1.65.0" gem "rubocop-rake", "~> 0.6.0" - gem "simplecov", "~> 0.21.2" - gem "webmock", "~> 3.14.0" + gem "simplecov", "~> 0.22.0" + gem "webmock", "~> 3.18.1" gem "yard", "~> 0.9.27" end diff --git a/gemfiles/faraday_1.gemfile.lock b/gemfiles/faraday_1.gemfile.lock index f11db11..7d8dcd6 100644 --- a/gemfiles/faraday_1.gemfile.lock +++ b/gemfiles/faraday_1.gemfile.lock @@ -1,26 +1,42 @@ PATH remote: .. specs: - duffel_api (0.2.0) + duffel_api (0.4.0) base16 (~> 0.0.2) faraday (>= 0.9.2, < 3) GEM remote: https://rubygems.org/ specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - appraisal (2.4.1) + activesupport (7.1.3.4) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + appraisal (2.5.0) bundler rake thor (>= 0.14.0) ast (2.4.2) base16 (0.0.2) + base64 (0.2.0) + bigdecimal (3.1.8) coderay (1.1.3) - crack (0.4.5) + concurrent-ruby (1.3.3) + connection_pool (2.4.1) + crack (1.0.0) + bigdecimal rexml - diff-lcs (1.5.0) + diff-lcs (1.5.1) docile (1.4.0) + drb (2.2.1) faraday (1.8.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -40,95 +56,122 @@ GEM faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - gc_ruboconfig (2.32.0) - rubocop (>= 1.25) - rubocop-performance (>= 1.13) - rubocop-rspec (>= 2.8.0) - hashdiff (1.0.1) - method_source (1.0.0) - multipart-post (2.1.1) - parallel (1.21.0) - parser (3.1.0.0) + gc_ruboconfig (5.0.1) + rubocop (>= 1.63) + rubocop-factory_bot (>= 2.26.1) + rubocop-performance (>= 1.21) + rubocop-rails (>= 2.25.0) + rubocop-rspec (>= 3.0.1) + rubocop-rspec_rails (>= 2.30.0) + hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) + json (2.7.2) + language_server-protocol (3.17.0.3) + method_source (1.1.0) + minitest (5.24.1) + multipart-post (2.4.1) + mutex_m (0.2.0) + parallel (1.25.1) + parser (3.3.4.0) ast (~> 2.4.1) - pry (0.14.1) + racc + pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (4.0.6) + public_suffix (6.0.0) + racc (1.8.0) + rack (3.1.7) rainbow (3.1.1) - rake (13.0.6) - regexp_parser (2.2.0) - rexml (3.2.5) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) + rake (13.2.1) + regexp_parser (2.9.2) + rexml (3.3.1) + strscan + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.3) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) + rspec-support (~> 3.12.0) rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.11.0) + rspec-mocks (3.12.7) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-support (3.11.0) - rspec_junit_formatter (0.5.1) + rspec-support (~> 3.12.0) + rspec-support (3.12.2) + rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.25.1) + rubocop (1.65.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.15.1, < 2.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.15.1) - parser (>= 3.0.1.1) - rubocop-performance (1.13.2) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) + rubocop-factory_bot (2.26.1) + rubocop (~> 1.61) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.25.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - rubocop-rspec (2.8.0) - rubocop (~> 1.19) - ruby-progressbar (1.11.0) + rubocop-rspec (3.0.3) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) + ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) - simplecov (0.21.2) + simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) - simplecov_json_formatter (0.1.3) - thor (1.2.1) - unicode-display_width (2.1.0) - webmock (3.14.0) + simplecov_json_formatter (0.1.4) + strscan (3.1.0) + thor (1.3.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) + webmock (3.18.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.7.0) - yard (0.9.27) - webrick (~> 1.7.0) + yard (0.9.36) PLATFORMS + arm64-darwin-23 x86_64-darwin-20 DEPENDENCIES appraisal (~> 2.4) duffel_api! faraday (= 1.8.0) - gc_ruboconfig (~> 2.32.0) + gc_ruboconfig (~> 5.0.1) pry (~> 0.14.1) rake (~> 13.0) - rspec (~> 3.11.0) + rspec (~> 3.12.0) rspec-its (~> 1.3.0) - rspec_junit_formatter (~> 0.5.0) - rubocop (~> 1.25.0) + rspec_junit_formatter (~> 0.6.0) + rubocop (~> 1.65.0) rubocop-rake (~> 0.6.0) - simplecov (~> 0.21.2) - webmock (~> 3.14.0) + simplecov (~> 0.22.0) + webmock (~> 3.18.1) yard (~> 0.9.27) BUNDLED WITH diff --git a/gemfiles/faraday_2.gemfile b/gemfiles/faraday_2.gemfile index 81fd5cd..3452c11 100644 --- a/gemfiles/faraday_2.gemfile +++ b/gemfiles/faraday_2.gemfile @@ -7,16 +7,17 @@ source "https://rubygems.org" gem "faraday", "2.0.1" group :development, :test do - gem "gc_ruboconfig", "~> 2.32.0" + gem "appraisal", "~> 2.4" + gem "gc_ruboconfig", "~> 5.0.1" gem "pry", "~> 0.14.1" gem "rake", "~> 13.0" - gem "rspec", "~> 3.11.0" + gem "rspec", "~> 3.12.0" gem "rspec-its", "~> 1.3.0" - gem "rspec_junit_formatter", "~> 0.5.0" - gem "rubocop", "~> 1.25.0" + gem "rspec_junit_formatter", "~> 0.6.0" + gem "rubocop", "~> 1.65.0" gem "rubocop-rake", "~> 0.6.0" - gem "simplecov", "~> 0.21.2" - gem "webmock", "~> 3.14.0" + gem "simplecov", "~> 0.22.0" + gem "webmock", "~> 3.18.1" gem "yard", "~> 0.9.27" end diff --git a/gemfiles/faraday_2.gemfile.lock b/gemfiles/faraday_2.gemfile.lock index 039592c..92f49b3 100644 --- a/gemfiles/faraday_2.gemfile.lock +++ b/gemfiles/faraday_2.gemfile.lock @@ -1,118 +1,161 @@ PATH remote: .. specs: - duffel_api (0.2.0) + duffel_api (0.4.0) base16 (~> 0.0.2) faraday (>= 0.9.2, < 3) GEM remote: https://rubygems.org/ specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - appraisal (2.4.1) + activesupport (7.1.3.4) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + appraisal (2.5.0) bundler rake thor (>= 0.14.0) ast (2.4.2) base16 (0.0.2) + base64 (0.2.0) + bigdecimal (3.1.8) coderay (1.1.3) - crack (0.4.5) + concurrent-ruby (1.3.3) + connection_pool (2.4.1) + crack (1.0.0) + bigdecimal rexml - diff-lcs (1.5.0) + diff-lcs (1.5.1) docile (1.4.0) + drb (2.2.1) faraday (2.0.1) faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) - faraday-net_http (2.0.1) - gc_ruboconfig (2.32.0) - rubocop (>= 1.25) - rubocop-performance (>= 1.13) - rubocop-rspec (>= 2.8.0) - hashdiff (1.0.1) - method_source (1.0.0) - parallel (1.21.0) - parser (3.1.0.0) + faraday-net_http (2.1.0) + gc_ruboconfig (5.0.1) + rubocop (>= 1.63) + rubocop-factory_bot (>= 2.26.1) + rubocop-performance (>= 1.21) + rubocop-rails (>= 2.25.0) + rubocop-rspec (>= 3.0.1) + rubocop-rspec_rails (>= 2.30.0) + hashdiff (1.1.0) + i18n (1.14.5) + concurrent-ruby (~> 1.0) + json (2.7.2) + language_server-protocol (3.17.0.3) + method_source (1.1.0) + minitest (5.24.1) + mutex_m (0.2.0) + parallel (1.25.1) + parser (3.3.4.0) ast (~> 2.4.1) - pry (0.14.1) + racc + pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (4.0.6) + public_suffix (6.0.0) + racc (1.8.0) + rack (3.1.7) rainbow (3.1.1) - rake (13.0.6) - regexp_parser (2.2.0) - rexml (3.2.5) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.0) + rake (13.2.1) + regexp_parser (2.9.2) + rexml (3.3.1) + strscan + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.3) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) + rspec-support (~> 3.12.0) rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.11.0) + rspec-mocks (3.12.7) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-support (3.11.0) - rspec_junit_formatter (0.5.1) + rspec-support (~> 3.12.0) + rspec-support (3.12.2) + rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.25.1) + rubocop (1.65.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.15.1, < 2.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.15.1) - parser (>= 3.0.1.1) - rubocop-performance (1.13.2) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) + rubocop-factory_bot (2.26.1) + rubocop (~> 1.61) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.25.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - rubocop-rspec (2.8.0) - rubocop (~> 1.19) - ruby-progressbar (1.11.0) + rubocop-rspec (3.0.3) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) + ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) - simplecov (0.21.2) + simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) - simplecov_json_formatter (0.1.3) - thor (1.2.1) - unicode-display_width (2.1.0) - webmock (3.14.0) + simplecov_json_formatter (0.1.4) + strscan (3.1.0) + thor (1.3.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) + webmock (3.18.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.7.0) - yard (0.9.27) - webrick (~> 1.7.0) + yard (0.9.36) PLATFORMS + arm64-darwin-23 x86_64-darwin-20 DEPENDENCIES appraisal (~> 2.4) duffel_api! faraday (= 2.0.1) - gc_ruboconfig (~> 2.32.0) + gc_ruboconfig (~> 5.0.1) pry (~> 0.14.1) rake (~> 13.0) - rspec (~> 3.11.0) + rspec (~> 3.12.0) rspec-its (~> 1.3.0) - rspec_junit_formatter (~> 0.5.0) - rubocop (~> 1.25.0) + rspec_junit_formatter (~> 0.6.0) + rubocop (~> 1.65.0) rubocop-rake (~> 0.6.0) - simplecov (~> 0.21.2) - webmock (~> 3.14.0) + simplecov (~> 0.22.0) + webmock (~> 3.18.1) yard (~> 0.9.27) BUNDLED WITH diff --git a/lib/duffel_api.rb b/lib/duffel_api.rb index 5edbbcb..83fc1df 100644 --- a/lib/duffel_api.rb +++ b/lib/duffel_api.rb @@ -15,6 +15,7 @@ require_relative "duffel_api/resources/aircraft" require_relative "duffel_api/resources/airline" require_relative "duffel_api/resources/airport" +require_relative "duffel_api/resources/city" require_relative "duffel_api/resources/offer" require_relative "duffel_api/resources/offer_passenger" require_relative "duffel_api/resources/offer_request" @@ -33,6 +34,7 @@ require_relative "duffel_api/services/aircraft_service" require_relative "duffel_api/services/airlines_service" require_relative "duffel_api/services/airports_service" +require_relative "duffel_api/services/cities_service" require_relative "duffel_api/services/offer_passengers_service" require_relative "duffel_api/services/offer_requests_service" require_relative "duffel_api/services/offers_service" diff --git a/lib/duffel_api/client.rb b/lib/duffel_api/client.rb index c6fc401..68cce8f 100644 --- a/lib/duffel_api/client.rb +++ b/lib/duffel_api/client.rb @@ -30,6 +30,11 @@ def airports @airports ||= Services::AirportsService.new(@api_service) end + # @return [Services::CitiesService] + def cities + @cities ||= Services::CitiesService.new(@api_service) + end + # @return [Services::OfferPassengersService] def offer_passengers @offer_passengers ||= Services::OfferPassengersService.new(@api_service) diff --git a/lib/duffel_api/middlewares/rate_limiter.rb b/lib/duffel_api/middlewares/rate_limiter.rb index e623008..73b8281 100644 --- a/lib/duffel_api/middlewares/rate_limiter.rb +++ b/lib/duffel_api/middlewares/rate_limiter.rb @@ -15,7 +15,7 @@ def mutex end def initialize(app, options = {}) - super(app, options) + super end def call(env) diff --git a/lib/duffel_api/resources/aircraft.rb b/lib/duffel_api/resources/aircraft.rb index 8948b69..ca6824f 100644 --- a/lib/duffel_api/resources/aircraft.rb +++ b/lib/duffel_api/resources/aircraft.rb @@ -20,7 +20,7 @@ def initialize(object, response = nil) @id = object["id"] @name = object["name"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/airline.rb b/lib/duffel_api/resources/airline.rb index 36a8617..5384f61 100644 --- a/lib/duffel_api/resources/airline.rb +++ b/lib/duffel_api/resources/airline.rb @@ -28,7 +28,7 @@ def initialize(object, response = nil) @logo_lockup_url = object["logo_lockup_url"] @logo_symbol_url = object["logo_symbol_url"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/airport.rb b/lib/duffel_api/resources/airport.rb index ec6f4ca..5589cf5 100644 --- a/lib/duffel_api/resources/airport.rb +++ b/lib/duffel_api/resources/airport.rb @@ -4,7 +4,7 @@ module DuffelAPI module Resources class Airport < BaseResource - # @return [Hash, nil] + # @return [DuffelAPI::Resources::City, nil] attr_reader :city # @return [String] @@ -37,7 +37,7 @@ class Airport < BaseResource def initialize(object, response = nil) @object = object - @city = object["city"] + @city = object["city"].nil? ? object["city"] : City.new(object["city"]) @city_name = object["city_name"] @iata_code = object["iata_code"] @iata_country_code = object["iata_country_code"] @@ -48,7 +48,7 @@ def initialize(object, response = nil) @name = object["name"] @time_zone = object["time_zone"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/city.rb b/lib/duffel_api/resources/city.rb new file mode 100644 index 0000000..fc95633 --- /dev/null +++ b/lib/duffel_api/resources/city.rb @@ -0,0 +1,31 @@ +# encoding: utf-8 +# frozen_string_literal: true + +module DuffelAPI + module Resources + class City < BaseResource + # @return [String] + attr_reader :iata_code + + # @return [String] + attr_reader :iata_country_code + + # @return [String] + attr_reader :id + + # @return [String] + attr_reader :name + + def initialize(object, response = nil) + @object = object + + @iata_code = object["iata_code"] + @iata_country_code = object["iata_country_code"] + @id = object["id"] + @name = object["name"] + + super + end + end + end +end diff --git a/lib/duffel_api/resources/offer.rb b/lib/duffel_api/resources/offer.rb index 182bb2e..801f0f7 100644 --- a/lib/duffel_api/resources/offer.rb +++ b/lib/duffel_api/resources/offer.rb @@ -51,7 +51,7 @@ def initialize(object, response = nil) @total_emissions_kg = object["total_emissions_kg"] @updated_at = object["updated_at"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/offer_passenger.rb b/lib/duffel_api/resources/offer_passenger.rb index 414dea8..9e23e83 100644 --- a/lib/duffel_api/resources/offer_passenger.rb +++ b/lib/duffel_api/resources/offer_passenger.rb @@ -32,7 +32,7 @@ def initialize(object, response = nil) @family_name = object["family_name"] @age = object["age"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/offer_request.rb b/lib/duffel_api/resources/offer_request.rb index b407117..e66a8f7 100644 --- a/lib/duffel_api/resources/offer_request.rb +++ b/lib/duffel_api/resources/offer_request.rb @@ -36,7 +36,7 @@ def initialize(object, response = nil) @passengers = object["passengers"] @slices = object["slices"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/order.rb b/lib/duffel_api/resources/order.rb index 5452d27..785a126 100644 --- a/lib/duffel_api/resources/order.rb +++ b/lib/duffel_api/resources/order.rb @@ -49,7 +49,7 @@ def initialize(object, response = nil) @total_amount = object["total_amount"] @total_currency = object["total_currency"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/order_cancellation.rb b/lib/duffel_api/resources/order_cancellation.rb index 98e21a6..87d499e 100644 --- a/lib/duffel_api/resources/order_cancellation.rb +++ b/lib/duffel_api/resources/order_cancellation.rb @@ -27,7 +27,7 @@ def initialize(object, response = nil) @refund_currency = object["refund_currency"] @refund_to = object["refund_to"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/order_change.rb b/lib/duffel_api/resources/order_change.rb index f48167b..75fe02b 100644 --- a/lib/duffel_api/resources/order_change.rb +++ b/lib/duffel_api/resources/order_change.rb @@ -37,7 +37,7 @@ def initialize(object, response = nil) @refund_to = object["refund_to"] @slices = object["slices"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/order_change_offer.rb b/lib/duffel_api/resources/order_change_offer.rb index 3a898a3..f5693b2 100644 --- a/lib/duffel_api/resources/order_change_offer.rb +++ b/lib/duffel_api/resources/order_change_offer.rb @@ -37,7 +37,7 @@ def initialize(object, response = nil) @slices = object["slices"] @updated_at = object["updated_at"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/order_change_request.rb b/lib/duffel_api/resources/order_change_request.rb index 27a1ab8..b0f2e1b 100644 --- a/lib/duffel_api/resources/order_change_request.rb +++ b/lib/duffel_api/resources/order_change_request.rb @@ -23,7 +23,7 @@ def initialize(object, response = nil) @slices = object["slices"] @updated_at = object["updated_at"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/payment.rb b/lib/duffel_api/resources/payment.rb index 5601620..61bfbdb 100644 --- a/lib/duffel_api/resources/payment.rb +++ b/lib/duffel_api/resources/payment.rb @@ -19,7 +19,7 @@ def initialize(object, response = nil) @id = object["id"] @type = object["type"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/payment_intent.rb b/lib/duffel_api/resources/payment_intent.rb index d0d9d9a..3399b4d 100644 --- a/lib/duffel_api/resources/payment_intent.rb +++ b/lib/duffel_api/resources/payment_intent.rb @@ -43,7 +43,7 @@ def initialize(object, response = nil) @status = object["status"] @updated_at = object["updated_at"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/refund.rb b/lib/duffel_api/resources/refund.rb index 4804616..f3d0ff8 100644 --- a/lib/duffel_api/resources/refund.rb +++ b/lib/duffel_api/resources/refund.rb @@ -33,7 +33,7 @@ def initialize(object, response = nil) @status = object["status"] @updated_at = object["updated_at"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/seat_map.rb b/lib/duffel_api/resources/seat_map.rb index ed948e4..6d4e030 100644 --- a/lib/duffel_api/resources/seat_map.rb +++ b/lib/duffel_api/resources/seat_map.rb @@ -17,7 +17,7 @@ def initialize(object, response = nil) @segment_id = object["segment_id"] @slice_id = object["slice_id"] - super(object, response) + super end end end diff --git a/lib/duffel_api/resources/webhook.rb b/lib/duffel_api/resources/webhook.rb index 820ac8d..6913b0e 100644 --- a/lib/duffel_api/resources/webhook.rb +++ b/lib/duffel_api/resources/webhook.rb @@ -25,7 +25,7 @@ def initialize(object, response = nil) @updated_at = object["updated_at"] @url = object["url"] - super(object, response) + super end end end diff --git a/lib/duffel_api/services/cities_service.rb b/lib/duffel_api/services/cities_service.rb new file mode 100644 index 0000000..51464e7 --- /dev/null +++ b/lib/duffel_api/services/cities_service.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module DuffelAPI + module Services + class CitiesService < BaseService + # Lists cities, returning a single page of results + # + # @option [Hash] :params Parameters to include in the HTTP querystring, including + # any filters + # @return [ListResponse] + # @raise [Errors::Error] when the Duffel API returns an error + def list(options = {}) + path = "/air/cities" + + response = make_request(:get, path, options) + + ListResponse.new( + response: response, + unenveloped_body: unenvelope_body(response.parsed_body), + resource_class: Resources::City, + ) + end + + # Returns an `Enumerator` which can automatically cycle through multiple + # pages of `Resources::City`s. + # + # By default, this will use pages of 200 results under the hood, but this + # can be customised by specifying the `:limit` option in the `:params`. + # + # @param options [Hash] options passed to `#list`, for example `:params` to + # send an HTTP querystring with filters + # @return [Enumerator] + # @raise [Errors::Error] when the Duffel API returns an error + def all(options = {}) + options[:params] = DEFAULT_ALL_PARAMS.merge(options[:params] || {}) + + DuffelAPI::Paginator.new( + service: self, + options: options, + ).enumerator + end + + # Retrieves a single city by ID + # + # @param id [String] + # @return [Resources::City] + # @raise [Errors::Error] when the Duffel API returns an error + def get(id, options = {}) + path = substitute_url_pattern("/air/cities/:id", "id" => id) + + response = make_request(:get, path, options) + + return if response.raw_body.nil? + + Resources::City.new(unenvelope_body(response.parsed_body), response) + end + end + end +end diff --git a/spec/duffel_api/services/airports_service_spec.rb b/spec/duffel_api/services/airports_service_spec.rb index ca4ef1b..89b4834 100644 --- a/spec/duffel_api/services/airports_service_spec.rb +++ b/spec/duffel_api/services/airports_service_spec.rb @@ -197,16 +197,16 @@ it "returns an Airport resource" do expect(get_response).to be_a(DuffelAPI::Resources::Airport) - expect(get_response.city).to be_nil - expect(get_response.city_name).to eq("Mogadishu") - expect(get_response.iata_code).to eq("MGQ") - expect(get_response.iata_country_code).to eq("SO") - expect(get_response.icao_code).to eq("HCMM") - expect(get_response.id).to eq("arp_mgq_so") - expect(get_response.latitude).to eq(2.015817) - expect(get_response.longitude).to eq(45.304832) - expect(get_response.name).to eq("Aden Adde International Airport") - expect(get_response.time_zone).to eq("Africa/Mogadishu") + expect(get_response.city).to be_a(DuffelAPI::Resources::City) + expect(get_response.city_name).to eq("London") + expect(get_response.iata_code).to eq("LHR") + expect(get_response.iata_country_code).to eq("GB") + expect(get_response.icao_code).to eq("EGLL") + expect(get_response.id).to eq("arp_lhr_gb") + expect(get_response.latitude).to eq(51.470311) + expect(get_response.longitude).to eq(-0.458118) + expect(get_response.name).to eq("Heathrow Airport") + expect(get_response.time_zone).to eq("Europe/London") end it "exposes the API response" do diff --git a/spec/duffel_api/services/cities_service_spec.rb b/spec/duffel_api/services/cities_service_spec.rb new file mode 100644 index 0000000..c33f04d --- /dev/null +++ b/spec/duffel_api/services/cities_service_spec.rb @@ -0,0 +1,204 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe DuffelAPI::Services::CitiesService do + let(:client) do + DuffelAPI::Client.new( + access_token: "secret_token", + ) + end + + let(:response_headers) do + { + "content-type" => "application/json", + "x-request-id" => "FsJz79144I4JjDwAA6TB", + } + end + + describe "#list" do + describe "with no filters" do + subject(:get_list_response) { client.cities.list } + + let(:response_body) { load_fixture("cities/list.json") } + + let!(:stub) do + stub_request(:get, "https://api.duffel.com/air/cities").to_return( + body: response_body, + headers: response_headers, + ) + end + + it "makes the expected request to the Duffel API" do + get_list_response + expect(stub).to have_been_requested + end + + it "exposes valid City resources" do + expect(get_list_response.records.map(&:class).uniq). + to eq([DuffelAPI::Resources::City]) + + city = get_list_response.records.first + + expect(city.iata_code).to eq("ABI") + expect(city.iata_country_code).to eq("US") + expect(city.id).to eq("cit_abi_us") + expect(city.name).to eq("Abilene") + end + + it "exposes the cursors for before and after" do + expect(get_list_response.before).to be_nil + expect(get_list_response.after).to eq("g3QAAAACdwJpZG0AAAAKY2l0X2Nvc191c3" \ + "cEbmFtZW0AAAAQQ29sb3JhZG8gU3ByaW5ncw==") + end + + it "exposes the API response" do + api_response = get_list_response.api_response + + expect(api_response).to be_a(DuffelAPI::APIResponse) + + expect(api_response.body).to be_a(String) + expect(api_response.headers).to eq(response_headers) + expect(api_response.request_id).to eq(response_headers["x-request-id"]) + expect(api_response.status_code).to eq(200) + end + end + + describe "with parameters" do + subject(:get_list_response) { client.cities.list(params: { limit: 200 }) } + + let(:response_body) { load_fixture("cities/list.json") } + + let!(:stub) do + stub_request(:get, "https://api.duffel.com/air/cities"). + with(query: { "limit" => "200" }). + to_return( + body: response_body, + headers: response_headers, + ) + end + + it "makes the expected request to the Duffel API" do + get_list_response + expect(stub).to have_been_requested + end + end + end + + describe "#all" do + let(:first_page_response_body) { load_fixture("cities/list.json") } + + let(:last_page_response_body) do + convert_list_response_to_last_page(first_page_response_body) + end + + let(:expected_query_params) do + { limit: 200 } + end + + let!(:first_response_stub) do + stub_request(:get, "https://api.duffel.com/air/cities"). + with(query: expected_query_params). + to_return( + body: first_page_response_body, + headers: response_headers, + ) + end + + let!(:second_response_stub) do + stub_request(:get, "https://api.duffel.com/air/cities"). + with(query: expected_query_params.merge( + "after" => "g3QAAAACdwJpZG0AAAAKY2l0X2Nvc191c3cEbmFtZW0AAAAQQ29sb3JhZG8gU3B" \ + "yaW5ncw==", + )). + to_return( + body: last_page_response_body, + headers: response_headers, + ) + end + + it "automatically makes the requests to load all pages, 200 results at a time" do + expect(client.cities.all.to_a.length).to eq(100) + expect(first_response_stub).to have_been_requested + expect(second_response_stub).to have_been_requested + end + + it "exposes valid City resources" do + records = client.cities.all.to_a + expect(records.map(&:class).uniq).to eq([DuffelAPI::Resources::City]) + city = records.first + + expect(city.iata_code).to eq("ABI") + expect(city.iata_country_code).to eq("US") + expect(city.id).to eq("cit_abi_us") + expect(city.name).to eq("Abilene") + end + + it "exposes the API response" do + records = client.cities.all.to_a + api_response = records.first.api_response + + expect(api_response).to be_a(DuffelAPI::APIResponse) + + expect(api_response.body).to be_a(String) + expect(api_response.headers).to eq(response_headers) + expect(api_response.request_id).to eq(response_headers["x-request-id"]) + expect(api_response.status_code).to eq(200) + end + + context "customising the limit per page" do + let(:expected_query_params) do + { limit: 33 } + end + + it "requests the requested number of items per page from the API" do + client.cities.all(params: { limit: 33 }). + to_a + + expect(first_response_stub).to have_been_requested + expect(second_response_stub).to have_been_requested + end + end + end + + describe "#get" do + subject(:get_response) { client.cities.get(id) } + + let(:id) { "cit_lon_gb" } + + let!(:stub) do + stub_request(:get, "https://api.duffel.com/air/cities/cit_lon_gb"). + to_return( + body: response_body, + headers: response_headers, + ) + end + + let(:response_body) { load_fixture("cities/show.json") } + + it "makes the expected request to the Duffel API" do + get_response + expect(stub).to have_been_requested + end + + it "returns an Airport resource" do + expect(get_response).to be_a(DuffelAPI::Resources::City) + + expect(get_response.iata_code).to eq("LON") + expect(get_response.iata_country_code).to eq("GB") + expect(get_response.id).to eq("cit_lon_gb") + expect(get_response.name).to eq("London") + end + + it "exposes the API response" do + api_response = get_response.api_response + + expect(api_response).to be_a(DuffelAPI::APIResponse) + + expect(api_response.body).to be_a(String) + expect(api_response.headers).to eq(response_headers) + expect(api_response.request_id).to eq(response_headers["x-request-id"]) + expect(api_response.status_code).to eq(200) + end + end +end diff --git a/spec/duffel_api/services/offers_service_spec.rb b/spec/duffel_api/services/offers_service_spec.rb index 8152e19..7aad0c3 100644 --- a/spec/duffel_api/services/offers_service_spec.rb +++ b/spec/duffel_api/services/offers_service_spec.rb @@ -297,15 +297,16 @@ context "with parameters" do let!(:stub) do stub_request(:get, "https://api.duffel.com/air/offers/off_0000AEdGRhtp5AUUdJqMxo"). - with(query: { "return_available_services" => true }) - to_return( - body: response_body, - headers: response_headers, - ) - it "makes the expected request to the Duffel API" do - client.offers.get(id, params: { return_available_services: true }) - expect(stub).to have_been_requested - end + with(query: { "return_available_services" => true }). + to_return( + body: response_body, + headers: response_headers, + ) + end + + it "makes the expected request to the Duffel API" do + client.offers.get(id, params: { return_available_services: true }) + expect(stub).to have_been_requested end end end diff --git a/spec/fixtures/airports/show.json b/spec/fixtures/airports/show.json index 04b8ce8..26dfe22 100644 --- a/spec/fixtures/airports/show.json +++ b/spec/fixtures/airports/show.json @@ -1,14 +1,20 @@ { "data": { - "time_zone": "Africa/Mogadishu", - "name": "Aden Adde International Airport", - "longitude": 45.304832, - "latitude": 2.015817, - "id": "arp_mgq_so", - "icao_code": "HCMM", - "iata_country_code": "SO", - "iata_code": "MGQ", - "city_name": "Mogadishu", - "city": null + "city_name": "London", + "icao_code": "EGLL", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "LHR", + "latitude": 51.470311, + "longitude": -0.458118, + "city": { + "iata_country_code": "GB", + "iata_code": "LON", + "name": "London", + "id": "cit_lon_gb" + }, + "time_zone": "Europe/London", + "name": "Heathrow Airport", + "id": "arp_lhr_gb" } } diff --git a/spec/fixtures/cities/list.json b/spec/fixtures/cities/list.json new file mode 100644 index 0000000..1da9d89 --- /dev/null +++ b/spec/fixtures/cities/list.json @@ -0,0 +1,1801 @@ +{ + "meta": { + "before": null, + "limit": 50, + "after": "g3QAAAACdwJpZG0AAAAKY2l0X2Nvc191c3cEbmFtZW0AAAAQQ29sb3JhZG8gU3ByaW5ncw==" + }, + "data": [ + { + "airports": [ + { + "city_name": "Abilene", + "iata_city_code": "ABI", + "iata_country_code": "US", + "icao_code": "KABI", + "iata_code": "ABI", + "latitude": 32.411237, + "longitude": -99.681822, + "time_zone": "America/Chicago", + "name": "Abilene Regional Airport", + "id": "arp_abi_us" + }, + { + "city_name": "Abilene", + "iata_city_code": "ABI", + "iata_country_code": "US", + "icao_code": "KDYS", + "iata_code": "DYS", + "latitude": 32.420799, + "longitude": -99.854599, + "time_zone": "America/Chicago", + "name": "Dyess Air Force Base", + "id": "arp_dys_us" + } + ], + "iata_country_code": "US", + "iata_code": "ABI", + "name": "Abilene", + "id": "cit_abi_us" + }, + { + "airports": [ + { + "city_name": "Abu Dhabi", + "iata_city_code": "AUH", + "iata_country_code": "AE", + "icao_code": "OMAM", + "iata_code": "DHF", + "latitude": 24.249302, + "longitude": 54.548251, + "time_zone": "Asia/Dubai", + "name": "Al Dhafra Air Base", + "id": "arp_dhf_ae" + }, + { + "city_name": "Abu Dhabi", + "iata_city_code": "AUH", + "iata_country_code": "AE", + "icao_code": null, + "iata_code": "AYM", + "latitude": 24.464725, + "longitude": 54.610182, + "time_zone": "Asia/Dubai", + "name": "Yas Island Seaplane Base Airport", + "id": "arp_aym_ae" + }, + { + "city_name": "Abu Dhabi", + "iata_city_code": "AUH", + "iata_country_code": "AE", + "icao_code": "OMAA", + "iata_code": "AUH", + "latitude": 24.437469, + "longitude": 54.650586, + "time_zone": "Asia/Dubai", + "name": "Abu Dhabi International Airport", + "id": "arp_auh_ae" + }, + { + "city_name": "Abu Dhabi", + "iata_city_code": "AUH", + "iata_country_code": "AE", + "icao_code": "OMAD", + "iata_code": "AZI", + "latitude": 24.428556, + "longitude": 54.457014, + "time_zone": "Asia/Dubai", + "name": "Bateen Airport", + "id": "arp_azi_ae" + } + ], + "iata_country_code": "AE", + "iata_code": "AUH", + "name": "Abu Dhabi", + "id": "cit_auh_ae" + }, + { + "airports": [ + { + "city_name": "Aitape", + "iata_city_code": "ATP", + "iata_country_code": "PG", + "icao_code": "AYAI", + "iata_code": "ATP", + "latitude": -3.143579, + "longitude": 142.346516, + "time_zone": "Pacific/Port_Moresby", + "name": "Aitape Airport", + "id": "arp_atp_pg" + }, + { + "city_name": "Aitape", + "iata_city_code": "ATP", + "iata_country_code": "PG", + "icao_code": null, + "iata_code": "TAJ", + "latitude": -3.197688, + "longitude": 142.429805, + "time_zone": "Pacific/Port_Moresby", + "name": "Tadji Airport", + "id": "arp_taj_pg" + } + ], + "iata_country_code": "PG", + "iata_code": "ATP", + "name": "Aitape", + "id": "cit_atp_pg" + }, + { + "airports": [ + { + "city_name": "Akron", + "iata_city_code": "CAK", + "iata_country_code": "US", + "icao_code": "KCAK", + "iata_code": "CAK", + "latitude": 40.915548, + "longitude": -81.440739, + "time_zone": "America/New_York", + "name": "Akron–Canton Airport", + "id": "arp_cak_us" + }, + { + "city_name": "Akron", + "iata_city_code": "CAK", + "iata_country_code": "US", + "icao_code": "KAKR", + "iata_code": "AKC", + "latitude": 41.035888, + "longitude": -81.467633, + "time_zone": "America/New_York", + "name": "Akron Fulton International Airport", + "id": "arp_akc_us" + } + ], + "iata_country_code": "US", + "iata_code": "CAK", + "name": "Akron/Canton", + "id": "cit_cak_us" + }, + { + "airports": [ + { + "city_name": "Alamogordo", + "iata_city_code": "ALM", + "iata_country_code": "US", + "icao_code": "KALM", + "iata_code": "ALM", + "latitude": 32.840108, + "longitude": -105.9919, + "time_zone": "America/Denver", + "name": "Alamogordo White Sands Regional Airport", + "id": "arp_alm_us" + }, + { + "city_name": "Alamogordo", + "iata_city_code": "ALM", + "iata_country_code": "US", + "icao_code": "KHMN", + "iata_code": "HMN", + "latitude": 32.852501, + "longitude": -106.107002, + "time_zone": "America/Denver", + "name": "Holloman Air Force Base", + "id": "arp_hmn_us" + } + ], + "iata_country_code": "US", + "iata_code": "ALM", + "name": "Alamogordo", + "id": "cit_alm_us" + }, + { + "airports": [ + { + "city_name": "Alexandria", + "iata_city_code": "AEX", + "iata_country_code": "US", + "icao_code": "KAEX", + "iata_code": "AEX", + "latitude": 31.326149, + "longitude": -92.546915, + "time_zone": "America/Chicago", + "name": "Alexandria International Airport", + "id": "arp_aex_us" + }, + { + "city_name": "Alexandria", + "iata_city_code": "AEX", + "iata_country_code": "US", + "icao_code": "KESF", + "iata_code": "ESF", + "latitude": 31.394614, + "longitude": -92.295764, + "time_zone": "America/Chicago", + "name": "Esler Regional Airport", + "id": "arp_esf_us" + } + ], + "iata_country_code": "US", + "iata_code": "AEX", + "name": "Alexandria", + "id": "cit_aex_us" + }, + { + "airports": [ + { + "city_name": "Alexandria", + "iata_city_code": "ALY", + "iata_country_code": "EG", + "icao_code": "HEAX", + "iata_code": "ALY", + "latitude": 31.191435, + "longitude": 29.952488, + "time_zone": "Africa/Cairo", + "name": "El Nouzha Airport", + "id": "arp_aly_eg" + }, + { + "city_name": "Alexandria", + "iata_city_code": "ALY", + "iata_country_code": "EG", + "icao_code": "HEBA", + "iata_code": "HBE", + "latitude": 30.931803, + "longitude": 29.69568, + "time_zone": "Africa/Cairo", + "name": "Borg El Arab Airport", + "id": "arp_hbe_eg" + } + ], + "iata_country_code": "EG", + "iata_code": "ALY", + "name": "Alexandria", + "id": "cit_aly_eg" + }, + { + "airports": [ + { + "city_name": "Altus", + "iata_city_code": "LTS", + "iata_country_code": "US", + "icao_code": "KAXS", + "iata_code": "AXS", + "latitude": 34.698416, + "longitude": -99.337992, + "time_zone": "America/Chicago", + "name": "Altus/Quartz Mountain Regional Airport", + "id": "arp_axs_us" + }, + { + "city_name": "Altus", + "iata_city_code": "LTS", + "iata_country_code": "US", + "icao_code": "KLTS", + "iata_code": "LTS", + "latitude": 34.667099, + "longitude": -99.266701, + "time_zone": "America/Chicago", + "name": "Altus Air Force Base", + "id": "arp_lts_us" + } + ], + "iata_country_code": "US", + "iata_code": "LTS", + "name": "Altus", + "id": "cit_lts_us" + }, + { + "airports": [ + { + "city_name": "Amarillo", + "iata_city_code": "AMA", + "iata_country_code": "US", + "icao_code": "KAMA", + "iata_code": "AMA", + "latitude": 35.219956, + "longitude": -101.706679, + "time_zone": "America/Chicago", + "name": "Rick Husband Amarillo International Airport", + "id": "arp_ama_us" + }, + { + "city_name": "Amarillo", + "iata_city_code": "AMA", + "iata_country_code": "US", + "icao_code": "KTDW", + "iata_code": "TDW", + "latitude": 35.169989, + "longitude": -101.826954, + "time_zone": "America/Chicago", + "name": "Tradewind Airport", + "id": "arp_tdw_us" + } + ], + "iata_country_code": "US", + "iata_code": "AMA", + "name": "Amarillo", + "id": "cit_ama_us" + }, + { + "airports": [ + { + "city_name": "Amman", + "iata_city_code": "AMM", + "iata_country_code": "JO", + "icao_code": "OJAM", + "iata_code": "ADJ", + "latitude": 31.973712, + "longitude": 35.987633, + "time_zone": "Asia/Amman", + "name": "Amman Civil Airport", + "id": "arp_adj_jo" + }, + { + "city_name": "Amman", + "iata_city_code": "AMM", + "iata_country_code": "JO", + "icao_code": "OJAI", + "iata_code": "AMM", + "latitude": 31.72266, + "longitude": 35.992224, + "time_zone": "Asia/Amman", + "name": "Queen Alia International Airport", + "id": "arp_amm_jo" + } + ], + "iata_country_code": "JO", + "iata_code": "AMM", + "name": "Amman", + "id": "cit_amm_jo" + }, + { + "airports": [ + { + "city_name": "Anchorage", + "iata_city_code": "ANC", + "iata_country_code": "US", + "icao_code": "PAFR", + "iata_code": "FRN", + "latitude": 61.264454, + "longitude": -149.653852, + "time_zone": "America/Anchorage", + "name": "Bryant Army Heliport", + "id": "arp_frn_us" + }, + { + "city_name": "Anchorage", + "iata_city_code": "ANC", + "iata_country_code": "US", + "icao_code": "PANC", + "iata_code": "ANC", + "latitude": 61.175143, + "longitude": -149.99304, + "time_zone": "America/Anchorage", + "name": "Ted Stevens Anchorage International Airport", + "id": "arp_anc_us" + }, + { + "city_name": "Anchorage", + "iata_city_code": "ANC", + "iata_country_code": "US", + "icao_code": "PAED", + "iata_code": "EDF", + "latitude": 61.251878, + "longitude": -149.808422, + "time_zone": "America/Anchorage", + "name": "Elmendorf Air Force Base", + "id": "arp_edf_us" + }, + { + "city_name": "Anchorage", + "iata_city_code": "ANC", + "iata_country_code": "US", + "icao_code": "PAMR", + "iata_code": "MRI", + "latitude": 61.214603, + "longitude": -149.843405, + "time_zone": "America/Anchorage", + "name": "Merrill Field Airport", + "id": "arp_mri_us" + } + ], + "iata_country_code": "US", + "iata_code": "ANC", + "name": "Anchorage", + "id": "cit_anc_us" + }, + { + "airports": [ + { + "city_name": "Ankara", + "iata_city_code": "ANK", + "iata_country_code": "TR", + "icao_code": "LTAD", + "iata_code": "ANK", + "latitude": 39.949798, + "longitude": 32.688598, + "time_zone": "Europe/Istanbul", + "name": "Etimesgut Air Base", + "id": "arp_ank_tr" + }, + { + "city_name": "Ankara", + "iata_city_code": "ANK", + "iata_country_code": "TR", + "icao_code": "LTAC", + "iata_code": "ESB", + "latitude": 40.12627, + "longitude": 32.993385, + "time_zone": "Europe/Istanbul", + "name": "Esenboğa International Airport", + "id": "arp_esb_tr" + } + ], + "iata_country_code": "TR", + "iata_code": "ANK", + "name": "Ankara", + "id": "cit_ank_tr" + }, + { + "airports": [ + { + "city_name": "Apia", + "iata_city_code": "APW", + "iata_country_code": "WS", + "icao_code": "NSFA", + "iata_code": "APW", + "latitude": -13.830224, + "longitude": -172.008052, + "time_zone": "Pacific/Apia", + "name": "Faleolo International Airport", + "id": "arp_apw_ws" + }, + { + "city_name": "Apia", + "iata_city_code": "APW", + "iata_country_code": "WS", + "icao_code": "NSFI", + "iata_code": "FGI", + "latitude": -13.84844, + "longitude": -171.740968, + "time_zone": "Pacific/Apia", + "name": "Fagali'i Airport", + "id": "arp_fgi_ws" + } + ], + "iata_country_code": "WS", + "iata_code": "APW", + "name": "Apia", + "id": "cit_apw_ws" + }, + { + "airports": [ + { + "city_name": "Ardmore", + "iata_city_code": "ADM", + "iata_country_code": "US", + "icao_code": null, + "iata_code": "AHD", + "latitude": 34.146973, + "longitude": -97.122742, + "time_zone": "America/Chicago", + "name": "Ardmore Downtown Executive Airport", + "id": "arp_ahd_us" + }, + { + "city_name": "Ardmore", + "iata_city_code": "ADM", + "iata_country_code": "US", + "icao_code": "KADM", + "iata_code": "ADM", + "latitude": 34.302418, + "longitude": -97.021157, + "time_zone": "America/Chicago", + "name": "Ardmore Municipal Airport", + "id": "arp_adm_us" + } + ], + "iata_country_code": "US", + "iata_code": "ADM", + "name": "Ardmore", + "id": "cit_adm_us" + }, + { + "airports": [ + { + "city_name": "Atlanta", + "iata_city_code": "ATL", + "iata_country_code": "US", + "icao_code": "KATL", + "iata_code": "ATL", + "latitude": 33.638714, + "longitude": -84.4279, + "time_zone": "America/New_York", + "name": "Hartsfield-Jackson Atlanta International Airport", + "id": "arp_atl_us" + }, + { + "city_name": "Atlanta", + "iata_city_code": "ATL", + "iata_country_code": "US", + "icao_code": "KPDK", + "iata_code": "PDK", + "latitude": 33.875583, + "longitude": -84.303619, + "time_zone": "America/New_York", + "name": "Dekalb Peachtree Airport", + "id": "arp_pdk_us" + }, + { + "city_name": "Atlanta", + "iata_city_code": "ATL", + "iata_country_code": "US", + "icao_code": "KFTY", + "iata_code": "FTY", + "latitude": 33.777896, + "longitude": -84.521638, + "time_zone": "America/New_York", + "name": "Fulton County Airport", + "id": "arp_fty_us" + } + ], + "iata_country_code": "US", + "iata_code": "ATL", + "name": "Atlanta", + "id": "cit_atl_us" + }, + { + "airports": [ + { + "city_name": "Auckland", + "iata_city_code": "AKL", + "iata_country_code": "NZ", + "icao_code": "NZAA", + "iata_code": "AKL", + "latitude": -37.008148, + "longitude": 174.789684, + "time_zone": "Pacific/Auckland", + "name": "Auckland Airport", + "id": "arp_akl_nz" + } + ], + "iata_country_code": "NZ", + "iata_code": "AKL", + "name": "Auckland", + "id": "cit_akl_nz" + }, + { + "airports": [ + { + "city_name": "Augusta", + "iata_city_code": "AGS", + "iata_country_code": "US", + "icao_code": "KDNL", + "iata_code": "DNL", + "latitude": 33.466454, + "longitude": -82.038534, + "time_zone": "America/New_York", + "name": "Daniel Field", + "id": "arp_dnl_us" + }, + { + "city_name": "Augusta", + "iata_city_code": "AGS", + "iata_country_code": "US", + "icao_code": "KAGS", + "iata_code": "AGS", + "latitude": 33.370604, + "longitude": -81.96675, + "time_zone": "America/New_York", + "name": "Augusta Regional Airport", + "id": "arp_ags_us" + } + ], + "iata_country_code": "US", + "iata_code": "AGS", + "name": "Augusta", + "id": "cit_ags_us" + }, + { + "airports": [ + { + "city_name": "Austin", + "iata_city_code": "AUS", + "iata_country_code": "US", + "icao_code": "KAUS", + "iata_code": "AUS", + "latitude": 30.196466, + "longitude": -97.667519, + "time_zone": "America/Chicago", + "name": "Austin-Bergstrom International Airport", + "id": "arp_aus_us" + } + ], + "iata_country_code": "US", + "iata_code": "AUS", + "name": "Austin", + "id": "cit_aus_us" + }, + { + "airports": [ + { + "city_name": "Baku", + "iata_city_code": "BAK", + "iata_country_code": "AZ", + "icao_code": "UBTT", + "iata_code": "ZXT", + "latitude": 40.495968, + "longitude": 49.97472, + "time_zone": "Asia/Baku", + "name": "Zabrat Airport", + "id": "arp_zxt_az" + }, + { + "city_name": "Baku", + "iata_city_code": "BAK", + "iata_country_code": "AZ", + "icao_code": "UBBB", + "iata_code": "GYD", + "latitude": 40.466321, + "longitude": 50.049476, + "time_zone": "Asia/Baku", + "name": "Heydar Aliyev International Airport", + "id": "arp_gyd_az" + } + ], + "iata_country_code": "AZ", + "iata_code": "BAK", + "name": "Baku", + "id": "cit_bak_az" + }, + { + "airports": [ + { + "city_name": "Baltimore", + "iata_city_code": "BWI", + "iata_country_code": "US", + "icao_code": "KMTN", + "iata_code": "MTN", + "latitude": 39.326578, + "longitude": -76.41708, + "time_zone": "America/New_York", + "name": "Martin State Airport", + "id": "arp_mtn_us" + }, + { + "city_name": "Baltimore", + "iata_city_code": "BWI", + "iata_country_code": "US", + "icao_code": "KBWI", + "iata_code": "BWI", + "latitude": 39.176402, + "longitude": -76.668345, + "time_zone": "America/New_York", + "name": "Baltimore Washington International Thurgood Marshall Airport", + "id": "arp_bwi_us" + } + ], + "iata_country_code": "US", + "iata_code": "BWI", + "name": "Baltimore", + "id": "cit_bwi_us" + }, + { + "airports": [ + { + "city_name": "Bangkok", + "iata_city_code": "BKK", + "iata_country_code": "TH", + "icao_code": "VTBS", + "iata_code": "BKK", + "latitude": 13.691187, + "longitude": 100.748128, + "time_zone": "Asia/Bangkok", + "name": "Suvarnabhumi Airport", + "id": "arp_bkk_th" + }, + { + "city_name": "Bangkok", + "iata_city_code": "BKK", + "iata_country_code": "TH", + "icao_code": "VTBD", + "iata_code": "DMK", + "latitude": 13.912929, + "longitude": 100.6056, + "time_zone": "Asia/Bangkok", + "name": "Don Mueang International Airport", + "id": "arp_dmk_th" + } + ], + "iata_country_code": "TH", + "iata_code": "BKK", + "name": "Bangkok", + "id": "cit_bkk_th" + }, + { + "airports": [ + { + "city_name": null, + "iata_city_code": "EAP", + "iata_country_code": "FR", + "icao_code": "LFSB", + "iata_code": "BSL", + "latitude": 47.59409, + "longitude": 7.527331, + "time_zone": "Europe/Paris", + "name": "EuroAirport Basel-Mulhouse-Freiburg", + "id": "arp_bsl_ch" + }, + { + "city_name": "Mulhouse/Basel", + "iata_city_code": "EAP", + "iata_country_code": "FR", + "icao_code": "LFSB", + "iata_code": "MLH", + "latitude": 47.59818, + "longitude": 7.525496, + "time_zone": "Europe/Paris", + "name": "EuroAirport Basel Mulhouse Freiburg", + "id": "arp_mlh_fr" + }, + { + "city_name": "Basel", + "iata_city_code": "EAP", + "iata_country_code": "FR", + "icao_code": "LFSB", + "iata_code": "BSL", + "latitude": 47.59409, + "longitude": 7.52733, + "time_zone": "Europe/Paris", + "name": "EuroAirport Basel-Mulhouse-Freiburg", + "id": "arp_bsl_fr" + } + ], + "iata_country_code": "CH", + "iata_code": "EAP", + "name": "Basel/Mulhouse", + "id": "cit_eap_ch" + }, + { + "airports": [ + { + "city_name": "Beaumont", + "iata_city_code": "BPT", + "iata_country_code": "US", + "icao_code": "KBMT", + "iata_code": "BMT", + "latitude": 30.07052, + "longitude": -94.213826, + "time_zone": "America/Chicago", + "name": "Beaumont Municipal Airport", + "id": "arp_bmt_us" + }, + { + "city_name": "Beaumont", + "iata_city_code": "BPT", + "iata_country_code": "US", + "icao_code": "KBPT", + "iata_code": "BPT", + "latitude": 29.95207, + "longitude": -94.021041, + "time_zone": "America/Chicago", + "name": "Jack Brooks Regional Airport", + "id": "arp_bpt_us" + } + ], + "iata_country_code": "US", + "iata_code": "BPT", + "name": "Beaumont/Port Arthur", + "id": "cit_bpt_us" + }, + { + "airports": [ + { + "city_name": "Beijing", + "iata_city_code": "BJS", + "iata_country_code": "CN", + "icao_code": "ZBAD", + "iata_code": "PKX", + "latitude": 39.509945, + "longitude": 116.41092, + "time_zone": "Asia/Shanghai", + "name": "Beijing Daxing International Airport", + "id": "arp_pkx_cn" + }, + { + "city_name": "Beijing", + "iata_city_code": "BJS", + "iata_country_code": "CN", + "icao_code": "ZBAA", + "iata_code": "PEK", + "latitude": 40.080613, + "longitude": 116.602404, + "time_zone": "Asia/Shanghai", + "name": "Beijing Capital International Airport", + "id": "arp_pek_cn" + }, + { + "city_name": "Beijing", + "iata_city_code": "BJS", + "iata_country_code": "CN", + "icao_code": "ZBNY", + "iata_code": "NAY", + "latitude": 39.782699, + "longitude": 116.387926, + "time_zone": "Asia/Shanghai", + "name": "Beijing Nanyuan Airport", + "id": "arp_nay_cn" + } + ], + "iata_country_code": "CN", + "iata_code": "BJS", + "name": "Beijing", + "id": "cit_bjs_cn" + }, + { + "airports": [ + { + "city_name": "Belfast", + "iata_city_code": "BFS", + "iata_country_code": "GB", + "icao_code": "EGAC", + "iata_code": "BHD", + "latitude": 54.617857, + "longitude": -5.872165, + "time_zone": "Europe/London", + "name": "George Best Belfast City Airport", + "id": "arp_bhd_gb" + }, + { + "city_name": "Belfast", + "iata_city_code": "BFS", + "iata_country_code": "GB", + "icao_code": "EGAA", + "iata_code": "BFS", + "latitude": 54.658279, + "longitude": -6.217177, + "time_zone": "Europe/London", + "name": "Belfast International Airport", + "id": "arp_bfs_gb" + } + ], + "iata_country_code": "GB", + "iata_code": "BFS", + "name": "Belfast", + "id": "cit_bfs_gb" + }, + { + "airports": [ + { + "city_name": "Belgrade", + "iata_city_code": "BEG", + "iata_country_code": "RS", + "icao_code": "LYBE", + "iata_code": "BEG", + "latitude": 44.820559, + "longitude": 20.292378, + "time_zone": "Europe/Belgrade", + "name": "Belgrade Nikola Tesla Airport", + "id": "arp_beg_rs" + }, + { + "city_name": "Batajnica", + "iata_city_code": "BEG", + "iata_country_code": "RS", + "icao_code": "LYBT", + "iata_code": "BJY", + "latitude": 44.935079, + "longitude": 20.257138, + "time_zone": "Europe/Belgrade", + "name": "Batajnica Air Base", + "id": "arp_bjy_rs" + } + ], + "iata_country_code": "RS", + "iata_code": "BEG", + "name": "Belgrade", + "id": "cit_beg_rs" + }, + { + "airports": [ + { + "city_name": "Belize City", + "iata_city_code": "BZE", + "iata_country_code": "BZ", + "icao_code": "MZBZ", + "iata_code": "BZE", + "latitude": 17.537595, + "longitude": -88.308539, + "time_zone": "America/Belize", + "name": "Philip S. W. Goldson International Airport", + "id": "arp_bze_bz" + }, + { + "city_name": "Belize City", + "iata_city_code": "BZE", + "iata_country_code": "BZ", + "icao_code": null, + "iata_code": "TZA", + "latitude": 17.516191, + "longitude": -88.194597, + "time_zone": "America/Belize", + "name": "Belize City Municipal Airport", + "id": "arp_tza_bz" + } + ], + "iata_country_code": "BZ", + "iata_code": "BZE", + "name": "Belize City", + "id": "cit_bze_bz" + }, + { + "airports": [ + { + "city_name": "Belo Horizonte", + "iata_city_code": "BHZ", + "iata_country_code": "BR", + "icao_code": "SBCF", + "iata_code": "CNF", + "latitude": -19.634271, + "longitude": -43.964763, + "time_zone": "America/Sao_Paulo", + "name": "Tancredo Neves International Airport", + "id": "arp_cnf_br" + }, + { + "city_name": "Belo Horizonte", + "iata_city_code": "BHZ", + "iata_country_code": "BR", + "icao_code": "SBBH", + "iata_code": "PLU", + "latitude": -19.850524, + "longitude": -43.952745, + "time_zone": "America/Sao_Paulo", + "name": "Pierce County Airport", + "id": "arp_plu_br" + } + ], + "iata_country_code": "BR", + "iata_code": "BHZ", + "name": "Belo Horizonte", + "id": "cit_bhz_br" + }, + { + "airports": [ + { + "city_name": "Berlin", + "iata_city_code": "BER", + "iata_country_code": "DE", + "icao_code": "EDDT", + "iata_code": "TXL", + "latitude": 52.558044, + "longitude": 13.288889, + "time_zone": "Europe/Berlin", + "name": "Berlin Tegel Airport", + "id": "arp_txl_de" + }, + { + "city_name": "Berlin", + "iata_city_code": "BER", + "iata_country_code": "DE", + "icao_code": null, + "iata_code": "BER", + "latitude": 52.362307, + "longitude": 13.504906, + "time_zone": "Europe/Berlin", + "name": "Berlin Brandenburg Airport", + "id": "arp_ber_de" + }, + { + "city_name": "Berlin", + "iata_city_code": "BER", + "iata_country_code": "DE", + "icao_code": "EDDB", + "iata_code": "SXF", + "latitude": 52.381814, + "longitude": 13.522205, + "time_zone": "Europe/Berlin", + "name": "Berlin-Schönefeld Airport", + "id": "arp_sxf_de" + } + ], + "iata_country_code": "DE", + "iata_code": "BER", + "name": "Berlin", + "id": "cit_ber_de" + }, + { + "airports": [ + { + "city_name": "Bethel", + "iata_city_code": "BET", + "iata_country_code": "US", + "icao_code": "PABE", + "iata_code": "JBT", + "latitude": 60.782013, + "longitude": -161.743063, + "time_zone": "America/Anchorage", + "name": "Bethel Seaplane Base", + "id": "arp_jbt_us" + }, + { + "city_name": "Bethel", + "iata_city_code": "BET", + "iata_country_code": "US", + "icao_code": "PABE", + "iata_code": "BET", + "latitude": 60.779761, + "longitude": -161.837887, + "time_zone": "America/Anchorage", + "name": "Bethel Airport", + "id": "arp_bet_us" + } + ], + "iata_country_code": "US", + "iata_code": "BET", + "name": "Bethel", + "id": "cit_bet_us" + }, + { + "airports": [ + { + "city_name": "Blytheville", + "iata_city_code": "BYH", + "iata_country_code": "US", + "icao_code": "KHKA", + "iata_code": "HKA", + "latitude": 35.93796, + "longitude": -89.83193, + "time_zone": "America/Chicago", + "name": "Blytheville Municipal Airport", + "id": "arp_hka_us" + }, + { + "city_name": "Blytheville", + "iata_city_code": "BYH", + "iata_country_code": "US", + "icao_code": "KBYH", + "iata_code": "BYH", + "latitude": 35.962747, + "longitude": -89.94529, + "time_zone": "America/Chicago", + "name": "Arkansas International Airport", + "id": "arp_byh_us" + } + ], + "iata_country_code": "US", + "iata_code": "BYH", + "name": "Blytheville", + "id": "cit_byh_us" + }, + { + "airports": [ + { + "city_name": "Boston", + "iata_city_code": "BOS", + "iata_country_code": "US", + "icao_code": null, + "iata_code": "BNH", + "latitude": 42.352509, + "longitude": -71.025732, + "time_zone": "America/New_York", + "name": "Boston Harbor Seaplane Base", + "id": "arp_bnh_us" + }, + { + "city_name": "Boston", + "iata_city_code": "BOS", + "iata_country_code": "US", + "icao_code": "KBOS", + "iata_code": "BOS", + "latitude": 42.364956, + "longitude": -71.007381, + "time_zone": "America/New_York", + "name": "General Edward Lawrence Logan International Airport", + "id": "arp_bos_us" + }, + { + "city_name": "Portsmouth", + "iata_city_code": "BOS", + "iata_country_code": "US", + "icao_code": "KPSM", + "iata_code": "PSM", + "latitude": 43.079053, + "longitude": -70.822681, + "time_zone": "America/New_York", + "name": "Portsmouth International Airport", + "id": "arp_psm_us" + } + ], + "iata_country_code": "US", + "iata_code": "BOS", + "name": "Boston", + "id": "cit_bos_us" + }, + { + "airports": [ + { + "city_name": "Brunswick", + "iata_city_code": "SSI", + "iata_country_code": "US", + "icao_code": "KSSI", + "iata_code": "SSI", + "latitude": 31.152689, + "longitude": -81.390179, + "time_zone": "America/New_York", + "name": "Malcolm McKinnon Airport", + "id": "arp_ssi_us" + }, + { + "city_name": "Brunswick", + "iata_city_code": "SSI", + "iata_country_code": "US", + "icao_code": "KBQK", + "iata_code": "BQK", + "latitude": 31.256802, + "longitude": -81.466759, + "time_zone": "America/New_York", + "name": "Brunswick Golden Isles Airport", + "id": "arp_bqk_us" + } + ], + "iata_country_code": "US", + "iata_code": "SSI", + "name": "Brunswick", + "id": "cit_ssi_us" + }, + { + "airports": [ + { + "city_name": "Brussels", + "iata_city_code": "BRU", + "iata_country_code": "BE", + "icao_code": "EBBR", + "iata_code": "BRU", + "latitude": 50.90042, + "longitude": 4.484052, + "time_zone": "Europe/Brussels", + "name": "Brussels Airport", + "id": "arp_bru_be" + }, + { + "city_name": "Brussels", + "iata_city_code": "BRU", + "iata_country_code": "BE", + "icao_code": "EBCI", + "iata_code": "CRL", + "latitude": 50.46129, + "longitude": 4.457859, + "time_zone": "Europe/Brussels", + "name": "Brussels South Charleroi Airport", + "id": "arp_crl_be" + } + ], + "iata_country_code": "BE", + "iata_code": "BRU", + "name": "Brussels", + "id": "cit_bru_be" + }, + { + "airports": [ + { + "city_name": "Bucharest", + "iata_city_code": "BUH", + "iata_country_code": "RO", + "icao_code": "LROP", + "iata_code": "OTP", + "latitude": 44.57092, + "longitude": 26.084706, + "time_zone": "Europe/Bucharest", + "name": "Henri Coandă International Airport", + "id": "arp_otp_ro" + }, + { + "city_name": "Bucharest", + "iata_city_code": "BUH", + "iata_country_code": "RO", + "icao_code": "LRBS", + "iata_code": "BBU", + "latitude": 44.502897, + "longitude": 26.101912, + "time_zone": "Europe/Bucharest", + "name": "Băneasa International Airport", + "id": "arp_bbu_ro" + } + ], + "iata_country_code": "RO", + "iata_code": "BUH", + "name": "Bucharest", + "id": "cit_buh_ro" + }, + { + "airports": [ + { + "city_name": "Buenos Aires", + "iata_city_code": "BUE", + "iata_country_code": "AR", + "icao_code": "SABE", + "iata_code": "AEP", + "latitude": -34.558615, + "longitude": -58.416304, + "time_zone": "America/Argentina/Buenos_Aires", + "name": "Jorge Newbery Airfield", + "id": "arp_aep_ar" + }, + { + "city_name": "Buenos Aires", + "iata_city_code": "BUE", + "iata_country_code": "AR", + "icao_code": "SAEZ", + "iata_code": "EZE", + "latitude": -34.818602, + "longitude": -58.535314, + "time_zone": "America/Argentina/Buenos_Aires", + "name": "Ministro Pistarini International Airport", + "id": "arp_eze_ar" + } + ], + "iata_country_code": "AR", + "iata_code": "BUE", + "name": "Buenos Aires", + "id": "cit_bue_ar" + }, + { + "airports": [ + { + "city_name": "Cairo", + "iata_city_code": "CAI", + "iata_country_code": "GP", + "icao_code": null, + "iata_code": "CCE", + "latitude": 18.100423, + "longitude": -63.049779, + "time_zone": "America/Marigot", + "name": "Grand Case-Espérance Airport", + "id": "arp_cce_gp" + }, + { + "city_name": null, + "iata_city_code": "CAI", + "iata_country_code": "GP", + "icao_code": null, + "iata_code": "CCE", + "latitude": 18.100423, + "longitude": -63.049779, + "time_zone": "America/Marigot", + "name": "Grand Case-Espérance Airport", + "id": "arp_cce_eg" + }, + { + "city_name": "Cairo", + "iata_city_code": "CAI", + "iata_country_code": "EG", + "icao_code": "HECA", + "iata_code": "CAI", + "latitude": 30.121954, + "longitude": 31.40751, + "time_zone": "Africa/Cairo", + "name": "Cairo International Airport", + "id": "arp_cai_eg" + } + ], + "iata_country_code": "EG", + "iata_code": "CAI", + "name": "Cairo", + "id": "cit_cai_eg" + }, + { + "airports": [ + { + "city_name": "Campbell River", + "iata_city_code": "YBL", + "iata_country_code": "CA", + "icao_code": "CYBL", + "iata_code": "YBL", + "latitude": 49.951375, + "longitude": -125.270212, + "time_zone": "America/Vancouver", + "name": "Campbell River Airport", + "id": "arp_ybl_ca" + }, + { + "city_name": "Campbell River", + "iata_city_code": "YBL", + "iata_country_code": "CA", + "icao_code": null, + "iata_code": "YHH", + "latitude": 49.949302, + "longitude": -125.269567, + "time_zone": "America/Vancouver", + "name": "Campbell River Harbour Airport", + "id": "arp_yhh_ca" + } + ], + "iata_country_code": "CA", + "iata_code": "YBL", + "name": "Campbell River", + "id": "cit_ybl_ca" + }, + { + "airports": [ + { + "city_name": "Cannes", + "iata_city_code": "CEQ", + "iata_country_code": "FR", + "icao_code": "LFMD", + "iata_code": "CEQ", + "latitude": 43.544633, + "longitude": 6.953192, + "time_zone": "Europe/Paris", + "name": "Cannes – Mandelieu Airport", + "id": "arp_ceq_fr" + } + ], + "iata_country_code": "FR", + "iata_code": "CEQ", + "name": "Cannes", + "id": "cit_ceq_fr" + }, + { + "airports": [ + { + "city_name": "Casablanca", + "iata_city_code": "CAS", + "iata_country_code": "MA", + "icao_code": "GMMN", + "iata_code": "CMN", + "latitude": 33.366389, + "longitude": -7.587202, + "time_zone": "Africa/Casablanca", + "name": "Mohammed V International Airport", + "id": "arp_cmn_ma" + }, + { + "city_name": "Casablanca", + "iata_city_code": "CAS", + "iata_country_code": "MA", + "icao_code": "GMMC", + "iata_code": "CAS", + "latitude": 33.554704, + "longitude": -7.661528, + "time_zone": "Africa/Casablanca", + "name": "Anfa Airport", + "id": "arp_cas_ma" + } + ], + "iata_country_code": "MA", + "iata_code": "CAS", + "name": "Casablanca", + "id": "cit_cas_ma" + }, + { + "airports": [ + { + "city_name": "Charlotte", + "iata_city_code": "CLT", + "iata_country_code": "US", + "icao_code": "KCLT", + "iata_code": "CLT", + "latitude": 35.214201, + "longitude": -80.945207, + "time_zone": "America/New_York", + "name": "Charlotte Douglas International Airport", + "id": "arp_clt_us" + }, + { + "city_name": "Charlotte", + "iata_city_code": "CLT", + "iata_country_code": "US", + "icao_code": null, + "iata_code": "QWG", + "latitude": 35.212095, + "longitude": -80.669294, + "time_zone": "America/New_York", + "name": "Wilgrove Air Park", + "id": "arp_qwg_us" + } + ], + "iata_country_code": "US", + "iata_code": "CLT", + "name": "Charlotte", + "id": "cit_clt_us" + }, + { + "airports": [ + { + "city_name": "Cheyenne", + "iata_city_code": "CYS", + "iata_country_code": "US", + "icao_code": "KCYS", + "iata_code": "CYS", + "latitude": 41.154498, + "longitude": -104.81374, + "time_zone": "America/Denver", + "name": "Cheyenne Regional Airport", + "id": "arp_cys_us" + } + ], + "iata_country_code": "US", + "iata_code": "CYS", + "name": "Cheyenne", + "id": "cit_cys_us" + }, + { + "airports": [ + { + "city_name": "Chicago", + "iata_city_code": "CHI", + "iata_country_code": "US", + "icao_code": "KORD", + "iata_code": "ORD", + "latitude": 41.976381, + "longitude": -87.90606, + "time_zone": "America/Chicago", + "name": "O'Hare International Airport", + "id": "arp_ord_us" + }, + { + "city_name": "Chicago", + "iata_city_code": "CHI", + "iata_country_code": "US", + "icao_code": "KMDW", + "iata_code": "MDW", + "latitude": 41.786336, + "longitude": -87.750029, + "time_zone": "America/Chicago", + "name": "Chicago Midway International Airport", + "id": "arp_mdw_us" + }, + { + "city_name": "Chicago", + "iata_city_code": "CHI", + "iata_country_code": "US", + "icao_code": "KRFD", + "iata_code": "RFD", + "latitude": 42.19732, + "longitude": -89.097969, + "time_zone": "America/Chicago", + "name": "Chicago Rockford International Airport", + "id": "arp_rfd_us" + }, + { + "city_name": "Chicago", + "iata_city_code": "CHI", + "iata_country_code": "US", + "icao_code": "KPWK", + "iata_code": "PWK", + "latitude": 42.11582, + "longitude": -87.901879, + "time_zone": "America/Chicago", + "name": "Chicago Executive Airport", + "id": "arp_pwk_us" + }, + { + "city_name": "Chicago", + "iata_city_code": "CHI", + "iata_country_code": "US", + "icao_code": "KDPA", + "iata_code": "DPA", + "latitude": 41.907279, + "longitude": -88.25084, + "time_zone": "America/Chicago", + "name": "DuPage Airport", + "id": "arp_dpa_us" + } + ], + "iata_country_code": "US", + "iata_code": "CHI", + "name": "Chicago", + "id": "cit_chi_us" + }, + { + "airports": [ + { + "city_name": "Chignik Lake", + "iata_city_code": "KCL", + "iata_country_code": "US", + "icao_code": null, + "iata_code": "KCQ", + "latitude": 56.254971, + "longitude": -158.772529, + "time_zone": "America/Anchorage", + "name": "Chignik Lake Airport", + "id": "arp_kcq_us" + }, + { + "city_name": "Chignik", + "iata_city_code": "KCL", + "iata_country_code": "US", + "icao_code": "PAJC", + "iata_code": "KCG", + "latitude": 56.310832, + "longitude": -158.373611, + "time_zone": "America/Anchorage", + "name": "Chignik Fisheries Airport", + "id": "arp_kcg_us" + }, + { + "city_name": "Chignik", + "iata_city_code": "KCL", + "iata_country_code": "US", + "icao_code": "PAJC", + "iata_code": "KCL", + "latitude": 56.311175, + "longitude": -158.535949, + "time_zone": "America/Anchorage", + "name": "Chignik Lagoon Airport", + "id": "arp_kcl_us" + }, + { + "city_name": "Chignik", + "iata_city_code": "KCL", + "iata_country_code": "US", + "icao_code": null, + "iata_code": "KBW", + "latitude": 56.295608, + "longitude": -158.40132, + "time_zone": "America/Anchorage", + "name": "Chignik Bay Airport", + "id": "arp_kbw_us" + } + ], + "iata_country_code": "US", + "iata_code": "KCL", + "name": "Chignik", + "id": "cit_kcl_us" + }, + { + "airports": [ + { + "city_name": "Cincinnati", + "iata_city_code": "CVG", + "iata_country_code": "US", + "icao_code": "KCVG", + "iata_code": "CVG", + "latitude": 39.051038, + "longitude": -84.665409, + "time_zone": "America/New_York", + "name": "Cincinnati/Northern Kentucky International Airport", + "id": "arp_cvg_us" + }, + { + "city_name": "Cincinnati", + "iata_city_code": "CVG", + "iata_country_code": "US", + "icao_code": "KLUK", + "iata_code": "LUK", + "latitude": 39.103433, + "longitude": -84.421367, + "time_zone": "America/New_York", + "name": "Cincinnati Municipal Airport", + "id": "arp_luk_us" + } + ], + "iata_country_code": "US", + "iata_code": "CVG", + "name": "Cincinnati", + "id": "cit_cvg_us" + }, + { + "airports": [ + { + "city_name": "Cleveland", + "iata_city_code": "CLE", + "iata_country_code": "US", + "icao_code": "KBKL", + "iata_code": "BKL", + "latitude": 41.514519, + "longitude": -81.686615, + "time_zone": "America/New_York", + "name": "Cleveland Burke Lakefront Airport", + "id": "arp_bkl_us" + }, + { + "city_name": "Cleveland", + "iata_city_code": "CLE", + "iata_country_code": "US", + "icao_code": "KCLE", + "iata_code": "CLE", + "latitude": 41.410408, + "longitude": -81.850364, + "time_zone": "America/New_York", + "name": "Cleveland Hopkins International Airport", + "id": "arp_cle_us" + }, + { + "city_name": "Cleveland", + "iata_city_code": "CLE", + "iata_country_code": "US", + "icao_code": "KCGF", + "iata_code": "CGF", + "latitude": 41.565789, + "longitude": -81.487719, + "time_zone": "America/New_York", + "name": "Cuyahoga County Airport", + "id": "arp_cgf_us" + } + ], + "iata_country_code": "US", + "iata_code": "CLE", + "name": "Cleveland", + "id": "cit_cle_us" + }, + { + "airports": [ + { + "city_name": "Clinton", + "iata_city_code": "CSM", + "iata_country_code": "US", + "icao_code": "KCSM", + "iata_code": "CSM", + "latitude": 35.347016, + "longitude": -99.198301, + "time_zone": "America/Chicago", + "name": "Clinton Sherman Airport", + "id": "arp_csm_us" + }, + { + "city_name": "Clinton", + "iata_city_code": "CSM", + "iata_country_code": "US", + "icao_code": "KCLK", + "iata_code": "CLK", + "latitude": 35.538317, + "longitude": -98.932739, + "time_zone": "America/Chicago", + "name": "Clinton Regional Airport", + "id": "arp_clk_us" + } + ], + "iata_country_code": "US", + "iata_code": "CSM", + "name": "Clinton", + "id": "cit_csm_us" + }, + { + "airports": [ + { + "city_name": "Clovis", + "iata_city_code": "CVN", + "iata_country_code": "US", + "icao_code": "KCVS", + "iata_code": "CVS", + "latitude": 34.385129, + "longitude": -103.320767, + "time_zone": "America/Denver", + "name": "Cannon Air Force Base", + "id": "arp_cvs_us" + }, + { + "city_name": "Clovis", + "iata_city_code": "CVN", + "iata_country_code": "US", + "icao_code": "KCVN", + "iata_code": "CVN", + "latitude": 34.425868, + "longitude": -103.078707, + "time_zone": "America/Denver", + "name": "Clovis Municipal Airport", + "id": "arp_cvn_us" + } + ], + "iata_country_code": "US", + "iata_code": "CVN", + "name": "Clovis", + "id": "cit_cvn_us" + }, + { + "airports": [ + { + "city_name": "Colombo", + "iata_city_code": "CMB", + "iata_country_code": "LK", + "icao_code": "VCBI", + "iata_code": "CMB", + "latitude": 7.180457, + "longitude": 79.884176, + "time_zone": "Asia/Colombo", + "name": "Bandaranaike International Airport", + "id": "arp_cmb_lk" + }, + { + "city_name": "Colombo", + "iata_city_code": "CMB", + "iata_country_code": "LK", + "icao_code": "VCCC", + "iata_code": "RML", + "latitude": 6.822141, + "longitude": 79.88773, + "time_zone": "Asia/Colombo", + "name": "Ratmalana Airport", + "id": "arp_rml_lk" + }, + { + "city_name": "Colombo", + "iata_city_code": "CMB", + "iata_country_code": "LK", + "icao_code": null, + "iata_code": "BYV", + "latitude": 6.92883, + "longitude": 79.854596, + "time_zone": "Asia/Colombo", + "name": "Beira Lake Seaplane Base Airport", + "id": "arp_byv_lk" + }, + { + "city_name": "Colombo", + "iata_city_code": "CMB", + "iata_country_code": "LK", + "icao_code": null, + "iata_code": "KEZ", + "latitude": 6.85, + "longitude": 80.55, + "time_zone": "Asia/Colombo", + "name": "Kelaniya River Airport", + "id": "arp_kez_lk" + }, + { + "city_name": "Colombo", + "iata_city_code": "CMB", + "iata_country_code": "LK", + "icao_code": null, + "iata_code": "DGM", + "latitude": 7.1079, + "longitude": 79.8721, + "time_zone": "Asia/Colombo", + "name": "Dandugama Seaplane Base", + "id": "arp_dgm_lk" + } + ], + "iata_country_code": "LK", + "iata_code": "CMB", + "name": "Colombo", + "id": "cit_cmb_lk" + }, + { + "airports": [ + { + "city_name": "Colorado Springs", + "iata_city_code": "COS", + "iata_country_code": "US", + "icao_code": "KAFF", + "iata_code": "AFF", + "latitude": 38.970442, + "longitude": -104.814704, + "time_zone": "America/Denver", + "name": "United States Air Force Academy Airfield", + "id": "arp_aff_us" + }, + { + "city_name": "Colorado Springs", + "iata_city_code": "COS", + "iata_country_code": "US", + "icao_code": "KCOS", + "iata_code": "COS", + "latitude": 38.803756, + "longitude": -104.701799, + "time_zone": "America/Denver", + "name": "Colorado Springs Airport", + "id": "arp_cos_us" + }, + { + "city_name": "Colorado Springs", + "iata_city_code": "COS", + "iata_country_code": "US", + "icao_code": "KFCS", + "iata_code": "FCS", + "latitude": 38.678398, + "longitude": -104.757004, + "time_zone": "America/Denver", + "name": "Butts Army Airfield", + "id": "arp_fcs_us" + } + ], + "iata_country_code": "US", + "iata_code": "COS", + "name": "Colorado Springs", + "id": "cit_cos_us" + } + ] +} diff --git a/spec/fixtures/cities/show.json b/spec/fixtures/cities/show.json new file mode 100644 index 0000000..5467f30 --- /dev/null +++ b/spec/fixtures/cities/show.json @@ -0,0 +1,94 @@ +{ + "data": { + "airports": [ + { + "city_name": "London", + "icao_code": "EGLL", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "LHR", + "latitude": 51.470311, + "longitude": -0.458118, + "time_zone": "Europe/London", + "name": "Heathrow Airport", + "id": "arp_lhr_gb" + }, + { + "city_name": "London", + "icao_code": "EGKB", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "BQH", + "latitude": 51.331399, + "longitude": 0.030782, + "time_zone": "Europe/London", + "name": "London Biggin Hill Airport", + "id": "arp_bqh_gb" + }, + { + "city_name": "London", + "icao_code": "EGGW", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "LTN", + "latitude": 51.875482, + "longitude": -0.37004, + "time_zone": "Europe/London", + "name": "London Luton Airport", + "id": "arp_ltn_gb" + }, + { + "city_name": "London", + "icao_code": "EGLC", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "LCY", + "latitude": 51.505071, + "longitude": 0.052398, + "time_zone": "Europe/London", + "name": "London City Airport", + "id": "arp_lcy_gb" + }, + { + "city_name": "London", + "icao_code": "EGMC", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "SEN", + "latitude": 51.571075, + "longitude": 0.697117, + "time_zone": "Europe/London", + "name": "London Southend Airport", + "id": "arp_sen_gb" + }, + { + "city_name": "London", + "icao_code": "EGKK", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "LGW", + "latitude": 51.150882, + "longitude": -0.18617, + "time_zone": "Europe/London", + "name": "Gatwick Airport", + "id": "arp_lgw_gb" + }, + { + "city_name": "London", + "icao_code": "EGSS", + "iata_city_code": "LON", + "iata_country_code": "GB", + "iata_code": "STN", + "latitude": 51.885508, + "longitude": 0.236933, + "time_zone": "Europe/London", + "name": "London Stansted Airport", + "id": "arp_stn_gb" + } + ], + "iata_country_code": "GB", + "iata_code": "LON", + "name": "London", + "id": "cit_lon_gb" + } +}