Elixirのforce.com用ライブラリのforcexを使ってforce.comのAPIを叩いてみました。
設定
mixでプロジェクトを作成します$ mix new sfdc --module SFDC
$ cd sfdc
configファイルを編集します。
# config/config.exs
use Mix.Config
config :forcex, Forcex.Client,
username: "{username}",
password: "{password}",
security_token: "{security_token}",
client_id: "{client_id}",
client_secret: "{client_secret}"
config :forcex, :request_options,
timeout: 20000,
recv_timeout: :infinity
dependencyも変更
# mix.exs
defmodule SFDC.Mixfile do
use Mix.Project
def project do
[app: :sfdc,
version: "0.0.1",
elixir: "~> 1.2",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
def application do
[applications: [:logger, :forcex]]
end
defp deps do
[{:forcex, "~> 0.3"}
]
end
end
依存ライブラリを取得
$ mix deps.get
メインスクリプト↓
# {project_root}/main.exs
client = Forcex.Client.login |> Forcex.Client.locate_services
first_page = Forcex.query("select Id, Name from Account order by CreatedDate desc", client)
SFDC.show_record_name(first_page["records"])
if Map.has_key?(first_page, "nextRecordsUrl") do
SFDC.next_query(client, first_page)
end
モジュール↓
# {project_root}/lib/sfdc.ex
defmodule SFDC do
def next_query(client, current_page) do
next_page = current_page |> Map.get("nextRecordsUrl") |> Forcex.get(client)
show_record_name(next_page["records"])
if Map.has_key?(next_page, "nextRecordsUrl") do
next_query(client, next_page)
end
end
def show_record_name([]) do
end
def show_record_name([head | tail]) do
IO.puts head["Name"]
show_record_name(tail)
end
end
あとはプロジェクトルートでコンパイル&スクリプト実行すればOK。今回の例だと取引先名が標準出力に表示されます。
$ mix run main.exs
ちなみに、configを書かなくても以下の環境変数を設定して、接続先を決定することも出来ます。
- SALESFORCE_USERNAME
- SALESFORCE_PASSWORD
- SALESFORCE_SECURITY_TOKEN
- SALESFORCE_CLIENT_ID
- SALESFORCE_CLIENT_SECRET
接続環境とAPIバージョンの切り替え
issueを出したら対応していただきました!Can we change the endpoint for salesforce? · Issue #7 · jeffweiss/forcex
こんな感じで使います。
client = Forcex.Client.default_config |>
Forcex.Client.login(%Forcex.Client{endpoint: "https://test.salesforce.com", api_version: "34.0"}) |>
Forcex.Client.locate_services
ハマりどころ
forcexというよりElixir及びmixの使い方のところでハマったので以下、備忘録def application内の依存モジュールを入れないと以下のエラーが発生します。
** (exit) exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.47.0>,
#Reference<0.0.3.1489>, {:client, :undefined, {:metrics_ng, :metrics_dummy},
:hackney_ssl_transport, 'login.salesforce.com', 443, "login.salesforce.com",
[recv_timeout: :infinity, connect_timeout: 20000], nil, nil, nil, true,
:hackney_pool, :infinity, false, 5, false, 5, nil, nil, nil, :undefined,
:start, nil, :normal, false, false, false, :undefined, false, nil,
:waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity)
** (EXIT) no process
(stdlib) gen_server.erl:212: :gen_server.call/3
src/hackney_manager.erl:66: :hackney_manager.init_request/1
src/hackney_manager.erl:56: :hackney_manager.new_request/1
src/hackney_connect.erl:184: :hackney_connect.socket_from_pool/4
src/hackney_connect.erl:36: :hackney_connect.connect/5
src/hackney.erl:328: :hackney.request/5
lib/httpoison/base.ex:396: HTTPoison.Base.request/9
lib/forcex.ex:3: Forcex.request!/5
configを適切に設定しないとclient_idが不正だよ、と以下のエラーが発生します
20:57:13.564 [warn] Cannot log into SFDC API. Please ensure you have Forcex
properly configured. Got error code 400 and message %{"error" => "invalid_client_id",
"error_description" => "client identifier invalid"}
** (BadMapError) expected a map, got: {400, [%{"errorCode" => "URL_NOT_RESET",
"message" => "Destination URL not reset. The URL returned from login must be set"}]}
(stdlib) :maps.find("query", {400, [%{"errorCode" => "URL_NOT_RESET", "message" =>
"Destination URL not reset. The URL returned from login must be set"}]})
(elixir) lib/map.ex:131: Map.get/3
(forcex) lib/forcex.ex:99: Forcex.query/2
main.exs:2: (file)
(elixir) lib/code.ex:363: Code.require_file/2