class PostcodeService def lookup(postcode) # Avoid network calls when postcode is invalid return unless postcode.match(POSTCODE_REGEXP) result = nil begin # URI encoding only supports ASCII characters ascii_postcode = self.class.clean(postcode) response = Excon.get("https://api.postcodes.io/postcodes/#{ascii_postcode}", idempotent: true, timeout: 30, expects: [200]) parsed_response = JSON.parse(response.body) result = { location_code: parsed_response["result"]["codes"]["admin_district"], location_admin_district: parsed_response["result"]["admin_district"], } rescue Excon::Error => e Rails.logger.warn("Postcode lookup request was not successful: #{e} #{e.response.body}") rescue StandardError => e Rails.logger.error("Unexpected error with postcode lookup request: #{e}") end result end def self.clean(postcode) postcode.encode("ASCII", "UTF-8", invalid: :replace, undef: :replace, replace: "").delete(" ").upcase end end