Forcex
Elixir library for interacting with the Force.com REST API.
Usage
Add Forcex to your dependency list
defp deps do
[ {:forcex, "~> 0.4"}
]
endAt compile time Forcex will query the Force.com REST API and generate modules for all the SObjects you have configured and permission to see.
If you see a warning like
23:37:02.057 [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"}You will need to configure Forcex, as noted below, and then explicitly recompile Forcex
$ mix deps.clean forcex
$ mix deps.compile forcexYou can have Forcex generate modules at compile time using the accompanying Mix task.
$ mix compile.forcex
This can also be invoked automatically by adding Forcex to your project's compilers in mix.exs
compilers: [:forcex] ++ Mix.compilers,Bulk API Usage
Forcex has an example Bulk API query job controller. Here's roughly how that can work.
client = Forcex.Bulk.Client.login
[
"Account",
"Campaign",
"Contact",
"Lead",
"Opportunity",
"OpportunityLineItem",
]
|> Enum.map(fn sobject -> {sobject, ["select Id, Name from #{sobject}"]} end)
|> Enum.map(fn {sobject, queries} ->
Forcex.Bulk.JobController.start_link({:query, sobject, queries, client}) end)Configuration
The Forcex.Client is configured to read login information either from
application configuration:
config :forcex, Forcex.Client,
username: "user@example.com",
password: "my_super_secret_password",
security_token: "EMAILED_FROM_SALESFORCE",
client_id: "CONNECTED_APP_OAUTH_CLIENT_ID",
client_secret: "CONNECTED_APP_OAUTH_CLIENT_SECRET"or these environment variables:
SALESFORCE_USERNAMESALESFORCE_PASSWORDSALESFORCE_SECURITY_TOKENSALESFORCE_CLIENT_IDSALESFORCE_CLIENT_SECRET
HTTPoison request-specific options may also be configured:
config :forcex, :request_options,
timeout: 20000,
recv_timeout: :infinityFor steps on how to create a Connected App with OAuth keys and secrets, please see the Force.com REST API section on Connected Apps.
Currently, to be fully functional, the Forcex.Client must both login and
locate_services.
Pagination of results is entirely manual at the moment.
client = Forcex.Client.login |> Forcex.Client.locate_services
first_page = Forcex.query("select Id, Name from Account order by CreatedDate desc", client)
second_page = first_page |> Map.get("nextRecordsUrl") |> Forcex.get(client)Further Configuration
Forcex allows additional configuration of API endpoint and API version via the
%Forcex.Client{} struct. You may also use this mechanism if you have a
grant_type other than password.
This example shows how to use both an older API version and the SalesForce sandbox API.
Forcex.Client.default_config
|> Forcex.Client.login(%Forcex.Client{endpoint: "https://test.salesforce.com", api_version: "34.0"})Testing
Make sure dependencies are installed
mix deps.getTests can be run with
mix testTests can be run automatically when files change with
mix test.watch --stale
Tests mock the api calls to the Salesforce API using Mox to set expectations on
Forcex.Api.MockHttp.raw_request. To know what to put in a mock response just
run the client in iex and look for the debug logging response from http.ex.
Make sure not to scrub any responses for sensitive data before including them
in a commit.
Example assuming environment variables are in place with login info
% iex -S mix
iex(1)> client = Forcex.Client.login |> Forcex.Client.locate_services
14:40:27.858 file=forcex/lib/forcex/api/http.ex line=19 [debug] Elixir.Forcex.Api.Http.raw_request response=%{access_token: "redacted",...
14:40:28.222 file=forcex/lib/forcex/api/http.ex line=19 [debug] Elixir.Forcex.Api.Http.raw_request response=%{process: "/services/data/v41.0/process", search...
iex(2)> Forcex.query("select Id, Name from Account order by CreatedDate desc", client)
14:43:05.896 file=forcex/lib/forcex/api/http.ex line=19 [debug] Elixir.Forcex.Api.Http.raw_request response=%{done: false, nextRecordsUrl: "/services/data/v4
Just take the data after response= and throw it in a Mox expectation. See
existing tests for full examples
response = %{access_token: "redacted"}
Forcex.Api.MockHttp
|> expect(:raw_request, fn(:get, ^expected_url, _, ^auth_header, _) -> response end)Current State
See https://www.salesforce.com/us/developer/docs/api_rest/
- List API versions available
- Login (Username/Password/Client Key/Client Secret)
- Login (Web Server OAuth)
- Login (User-Agent OAuth)
- OAuth Refresh Token
- Resources by Version
- Limits
- Describe Global
- SObject Basic Information
- SObject Describe
- SObject Get Deleted
- SObject Get Updated
- SObject Named Layouts
- SObject Rows
- SObject Rows by External ID
- SObject ApprovalLayouts
- SObject CompactLayouts
- SObject Layouts
- SObject Blob Retrieve
- SObject Quick Actions
- SObject Suggested Articles for Case
- SObject User Password
- AppMenu
- Compact Layouts
- FlexiPage
- Process Approvals
- Process Rules
- Query
- QueryAll
- Quick Actions
- Search
- Search Scope and Order
- Search Result Layouts
- Recently Viewed Items
- Search Suggested Article Title Matches
- Tabs
- Themes
License
MIT License, see LICENSE