📍
[Ruby]FoursquareAPIを使って場所の名前からスポット情報を検索する
FoursquareのplaceAPIにSuggest Completion
というAPIがあります。
場所の名前を与えるとその名前に近い名前の場所情報を返してくれます。
実際にどんなパラメータを付与できて、どんなレスポンスが返ってくるかは上記のドキュメントを見てもらうとして、今回は
・場所の名前
・中心となる緯度・経度
をパラメータとして与え、
・id(Foursquare上のid)
・名前
・緯度経度
・FoursquareでのカテゴリーのiconURL
を取得できるようにRubyで実装してみます。
Client
require 'foursquare/response_body'
require 'foursquare/response_data'
module Foursquare
class Client
API_BASE_URL = 'https://api.foursquare.com/v2'
# FoursquareAPIに仕様変更があっても指定した日付時点での仕様でFoursquareAPIを利用できる
API_VERSION = '20210918'
RESPONSE_DATA_CLASS_MAPPING = {
minivenue: Foursquare::ResponseData::Minivenue
}
def initialize
@client_id = ENV['FOURSQAURE_CLIENT_ID']
@client_secret = ENV['FOURSQAURE_CLIENT_SECRET']
@version = API_VERSION
end
def suggest(query:, lat:, long:)
send_request(
data_class_name: :minivenue, # 取得した情報を詰めるClassの名前を指定する
path: 'venues/suggestcompletion',
params: {
query: query,
ll: "#{lat},#{long}" # カンマ区切りの文字列として与えます
}
)
end
private
def send_request(data_class_name:, path:, params:)
response = connection.get(path) do |req|
params.each do |k, v|
req.params[k] = v
end
end
response_body = JSON.parse(response.body)
meta = response_body['meta']
if meta['code'] == 200
Foursquare::ResponseBody.new(
target_data: response_body['response'],
data_class: data_class_of(data_class_name)
)
else
# エラーをRaiseするなど
end
end
# Faradayを使ってリクエストする
def connection
params = {
client_id: @client_id,
client_secret: @client_secret,
v: @version
}
@connection ||= Faraday.new(url: API_BASE_URL, params: params)
end
def data_class_of(data_class_name)
RESPONSE_DATA_CLASS_MAPPING.fetch(data_class_name)
end
end
end
Response
Foursquareから取得した配列,hashをそのまま使うこともできますが、使う値をクラスに詰めます。
これにより、もしfoursquareから取得できる情報のキーなどに変更があっても、取得したデータをクラスに詰めている箇所だけ変更すれば済むようになります。
module Foursquare
class ResponseBody
attr_reader :data
def initialize(target_data:, data_class:)
# 配列以外も扱うなら要変更
@data = target_data[data_class.array_key].map do |data|
data_class.new(data)
end
end
end
end
module Foursquare
class ResponseData
# Fousquareから取得されるデータの構造に変更があってもこのクラスを修正するだけでいい
class Minivenue
attr_reader :id
attr_reader :name
attr_reader :category_icon_url
ICON_SIZE_PX = 64
def self.array_key
'minivenues'
end
def initialize(data)
@id = data['id']
@name = data['name']
@location = data['location']
@category = set_category_icon_url(data['categories'])
end
def lat
@location['lat']
end
def long
@location['lng']
end
private
def set_category_icon_url(categories)
category = categories.find { |c| c['primary'] }
return nil if category.nil?
# アイコンの画像URLは次のように生成できます: https://developer.foursquare.com/docs/api-reference/venues/categories/#response-fields
@category_icon_url = "#{category['icon']['prefix']}#{ICON_SIZE_PX}#{category['icon']['suffix']}"
end
end
end
end
使い方
require 'foursquare/client'
# インスタンス生成
client = Foursquare::Client.new
# 検索する名前と中心となる緯度経度を与える
response = client.suggest(lat: 35.65783614386869, long: 139.74067705232687, query: 'ミラノ')
# responseは以下のように、`@data`に値を詰めたクラスの配列がセットされている
=> #<Foursquare::ResponseBody:0x000055686354e6a8
@data=
[#<Foursquare::ResponseData::Minivenue:0x000055686354e630
@category="https://ss3.4sqi.net/img/categories_v2/food/dessert_64.png",
@category_icon_url="https://ss3.4sqi.net/img/categories_v2/food/dessert_64.png",
@id="55efafa5498ef7f599dfe6ac",
@location={"address"=>"東麻布2-12-3", "city"=>"港区", "state"=>"東京都", "postalCode"=>"106-0044", "country"=>"JP", "lat"=>35.65740086958714, "lng"=>139.74130872695832, "distance"=>74},
@name="ミラノ ドルチェ トレ・スパーデ (Milano Dolce Tre Spade)">,
#<Foursquare::ResponseData::Minivenue:0x000055686354e540
@category="https://ss3.4sqi.net/img/categories_v2/nightlife/default_64.png",
@category_icon_url="https://ss3.4sqi.net/img/categories_v2/nightlife/default_64.png",
@id="4b910378f964a520129f33e3",
@location={"address"=>"銀座8-6-18", "crossStreet"=>"銀座カレラ弐番館ビル 4F", "city"=>"中央区", "state"=>"東京都", "country"=>"JP", "lat"=>35.66835498133474, "lng"=>139.7603679780853, "distance"=>2131},
@name="銀座ミラノクラブ">,
# 省略
response.data.first.name
=> "ミラノ ドルチェ トレ・スパーデ (Milano Dolce Tre Spade)"
Discussion