简体   繁体   中英

How do I return specific json keys/values from an API after a search, using the HTTParty gem?

At the moment I have a simple app that consumes an external API and allows a user to query and return json. It returns all keys/values but I would only like it to return lat and lon in json, or at least I would only like to show these two in my view. Here is my code:

locationiq_api.rb

class LocationiqApi
  include HTTParty

  BASE_URI = "https://eu1.locationiq.com/v1/search.php"

  attr_accessor :city

  def initialize(api_key, format = "json")
    @options = { key: api_key, format: format }
  end

  def find_coordinates(city)
    self.class.get(BASE_URI, query: @options.merge({ q: city }))
  end

  def handle_error
    if find_coordinates.code.to_i = 200
      find_coordinates.parsed_response
    else
      raise "Couldn't connect to LocationIQ Api"
    end
  end
end 

locations_controller.rb

class LocationsController < ApplicationController

  def index
    @search = LocationiqApi.new("pk.29313e52bff0240b650bb0573332121e").find_coordinates(params[:q])
  end
end

locations.html.erb

<main>
  <h1>Location Search</h1>
  <!-- Button to search find coordinates -->
  <%= form_tag(locations_path, method: :get) do %>
    <%= label_tag(:q, "Search: ") %>
    <%= text_field_tag(:q) %>
    <%= submit_tag("Find coordinates") %>
  <% end %><br>

  <h2>Search results:</h2>

</main>

<%= @search %>

Returned json:

[{"place_id":"100066","licence":"https:\/\/locationiq.com\/attribution","osm_type":"node","osm_id":"107775","boundingbox":["51.3473219","51.6673219","-0.2876474","0.0323526"],"lat":"51.5073219","lon":"-0.1276474","display_name":"London, Greater London, England, SW1A 2DX, United Kingdom","class":"place","type":"city","importance":0.9654895765402,"icon":"https:\/\/locationiq.org\/static\/images\/mapicons\/poi_place_city.p.20.png"}]

Supposing you have a JSON string that looks something like, as an example, this:

"[{\"place_id\":\"100066\",\"lat\":\"51.5073219\",\"lon\":\"-0.1276474\",\"class\":\"place\",\"type\":\"city\"}]"

Then you should be able to do (roughly speaking):

JSON.dump(
  JSON.
    parse(
      "[{\"place_id\":\"100066\",\"lat\":\"51.5073219\",\"lon\":\"-0.1276474\",\"class\":\"place\",\"type\":\"city\"}]"
    ).
    first.
    slice('lat', 'lon')
)

This should give you:

 => "{\"lat\":\"51.5073219\",\"lon\":\"-0.1276474\"}" 

Now, I recall that HTTParty may already convert the API reponse to a Ruby object (array or hash), so that JSON.dump may not be needed. And, there might be other fiddles you would like to do (eg, you could use with_indifferent_access if you prefer working with symbols as keys instead of strings).

Just to be clear, if you want this to be part of your class method, then you might do something like:

class LocationiqApi
  include HTTParty

  BASE_URI = "https://eu1.locationiq.com/v1/search.php"

  attr_accessor :city

  def initialize(api_key, format = "json")
    @options = { key: api_key, format: format }
  end

  def find_coordinates(city)
    JSON.dump(
      JSON.
        parse(
          self.class.get(BASE_URI, query: @options.merge({ q: city }))
        ).
        first.
        slice('lat', 'lon')
    )
  end

  def handle_error
    if find_coordinates.code.to_i = 200
      find_coordinates.parsed_response
    else
      raise "Couldn't connect to LocationIQ Api"
    end
  end
end

If self.class.get(BASE_URI, query: @options.merge({ q: city })) returns anything other than a valid JSON string that represents an array of hashes , then this will probably fail.

I suppose the key bits are:

  • You need to convert (parse) your JSON into something Ruby can work with;
  • Once parsed, you need to grab a hash from your array of hashes (assuming an array of hashes is always the result of the parsing);
  • You can use slice to use only those key-value pairs you want;
  • Then, since you stipulated you want to return JSON, you need to turn your Ruby object back into JSON using, for example JSON.dump . You could also use, I suppose, to_json . Whichever floats your boat.

Try this:

@search.map {|r| {lat: r['lat'], lon: r['lon']} }

Will be an array of hashes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM