7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 16

ElixirDesktopで作るスマホアプリ Part 12 GooglePlacesAPIとの通信

Posted at

はじめに

この記事はElixirアドベントカレンダー2024のシリーズ2、16日目の記事です

Google Places APIと通信する部分を作ります

Google Places APIとは

テキストや緯度経度から周辺の施設を検索するAPIです

今回はライブラリを使うほどでもないので、GoogleのAPIを直に叩きます

使用するAPIキーは以下を参考にして取得してください

ライブラリの追加

APIと通信を行うHTTP Clientを追加します

mix.exs
  defp deps do
    [
      ...
-     {:ex_machina, "~> 2.8.0", only: :test}
+     {:ex_machina, "~> 2.8.0", only: :test},
+     {:req, "~> 0.5.0"}      
    ]
  end

API通信部分作成

通信部分を実装します

APIエンドポイントやキーをモジュール定数として設定します

このモジュールでは以下の関数を実装します

テキスト検索を行う serach_by_text
緯度経度から周辺の施設を検索する near_search
一覧から詳細を取得する search_by_place_id
スポットの写真(写真はレスポンスにないのでIDを元に別APIを叩く)を取得するget_place_photo
住所から国と郵便番号を除外するsormat_address

基本的にAPIを叩いてレスポンスから必要なデータだけ取り出すだけです

defmodule Trarecord.GoogleApi do
  @base_url "https://maps.googleapis.com/maps/api/place/"
  @api_key Application.compile_env(:trarecord, :google_api_key)
  @key "key=#{@api_key}"
  @lang "&language=ja"

  def search_by_text(text) do
    (@base_url <> "textsearch/json?" <> @key <> "&query=#{text}" <> @lang)
    |> URI.encode()
    |> Req.post!(headers: [{"Content-Length", 0}])
    |> Map.get(:body)
    |> Map.get("results")
    |> Enum.map(fn result ->
      %{
        name: result["name"],
        address: result["formatted_address"] |> format_address(),
        lat: result["geometry"]["lat"],
        lng: result["geometry"]["lng"],
        place_id: result["place_id"],
        icon: result["icon"]
      }
    end)
  end

  def near_search(lat, lng) do
    (@base_url <>
       "nearbysearch/json?" <>
       @key <>
       "&location=#{lat},#{lng}" <>
       "&radius=500" <>
       @lang)
    |> URI.encode()
    |> Req.post!(headers: [{"Content-Length", 0}])
    |> Map.get(:body)
    |> Map.get("results")
    |> Enum.map(fn result ->
      %{
        name: result["name"],
        address: result["vicinity"],
        lat: result["geometry"]["lat"],
        lng: result["geometry"]["lng"],
        place_id: result["place_id"],
        icon: result["icon"]
      }
    end)
  end

  def search_by_place_id(id) do
    endpoint = "details/json?"
    ref = "&reference=#{id}"

    params = [
      "formatted_address",
      "geometry",
      "icon",
      "name",
      "formatted_phone_number",
      "place_id",
      "photos",
      "url",
      "website"
    ]

    fields = "&fields=#{Enum.join(params, ",")}"

    (@base_url <> endpoint <> @key <> ref <> fields <> @lang)
    |> URI.encode()
    |> Req.post!(headers: [{"Content-Length", 0}])
    |> Map.get(:body)
    |> Map.get("result")
    |> then(&[&1])
    |> Enum.map(fn result ->
      image =
        case result["photos"] do
          nil ->
            "/images/blank.png"

          photos ->
            List.first(photos) |> Map.get("photo_reference") |> get_place_photo()
        end

      %{
        name: result["name"],
        address: result["formatted_address"] |> format_address(),
        lat: result["geometry"]["location"]["lat"],
        lng: result["geometry"]["location"]["lng"],
        place_id: result["place_id"],
        icon: result["icon"],
        image: image,
        map_url: result["url"],
        website: result["website"],
        phone: result["formatted_phone_number"]
      }
    end)
    |> List.first()
  end

  def get_place_photo(photo_ref) do
    endpoint = "photo?"
    q = "&maxwidth=400&photoreference=#{photo_ref}"

    (@base_url <> endpoint <> @key <> q)
    |> URI.encode()
    |> Req.post!(redirect: false, headers: [{"Content-Length", 0}])
    |> Map.get(:headers)
    |> Enum.find_value(fn {k, v} -> if k == "location", do: v end)
    |> List.first()
  end

  def format_address(str) do
    str
    |> String.replace(~r/日本、/, "")
    |> String.replace(~r/〒\d{3}-?\d{4}/, "")
  end
end

スクリーンショット 2025-01-01 1.50.12.png

最後に

GooglePlacesAPIをElixirから叩いて必要なデータを取得するモジュールを作成しました

Elixirだとレスポンスを|>で繋いでデータを整形でき、シンプルにできて非常に楽でした

次は実際に使ってデータを保存する箇所を実装していきます

本記事は以上になりますありがとうございました

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?