defmodule Forcex do @moduledoc """ The main module for interacting with Salesforce """ require Logger @type client :: map @type forcex_response :: map | {number, any} | String.t @type method :: :get | :put | :post | :patch | :delete @api Application.get_env(:forcex, :api) || Forcex.Api.Http @spec json_request(method, String.t, map | String.t, list, list) :: forcex_response def json_request(method, url, body, headers, options) do @api.raw_request(method, url, format_body(body), headers, options) end @spec post(String.t, map | String.t, client) :: forcex_response def post(path, body \\ "", client) do url = client.endpoint <> path headers = [{"Content-Type", "application/json"}] json_request(:post, url, body, headers ++ client.authorization_header, []) end @spec patch(String.t, String.t, client) :: forcex_response def patch(path, body \\ "", client) do url = client.endpoint <> path headers = [{"Content-Type", "application/json"}] json_request(:patch, url, body, headers ++ client.authorization_header, []) end @spec delete(String.t, client) :: forcex_response def delete(path, client) do url = client.endpoint <> path @api.raw_request(:delete, url, "", client.authorization_header, []) end @spec get(String.t, map | String.t, list, client) :: forcex_response def get(path, body \\ "", headers \\ [], client) do url = client.endpoint <> path json_request(:get, url, body, headers ++ client.authorization_header, []) end @spec versions(client) :: forcex_response def versions(%Forcex.Client{} = client) do get("/services/data", client) end @spec services(client) :: forcex_response def services(%Forcex.Client{} = client) do get("/services/data/v#{client.api_version}", client) end @basic_services [ limits: :limits, describe_global: :sobjects, quick_actions: :quickActions, recently_viewed_items: :recent, tabs: :tabs, theme: :theme, ] for {function, service} <- @basic_services do @spec unquote(function)(client) :: forcex_response def unquote(function)(%Forcex.Client{} = client) do client |> service_endpoint(unquote(service)) |> get(client) end end @spec describe_sobject(String.t, client) :: forcex_response def describe_sobject(sobject, %Forcex.Client{} = client) do base = service_endpoint(client, :sobjects) "#{base}/#{sobject}/describe/" |> get(client) end def attachment_body(binary_path, %Forcex.Client{} = client) do base = service_endpoint(client, :sobjects) "#{base}/Attachment/#{binary_path}/Body" |> get(client) end @spec metadata_changes_since(String.t, String.t, client) :: forcex_response def metadata_changes_since(sobject, since, client) do base = service_endpoint(client, :sobjects) "#{base}/#{sobject}/describe/" |> get("", [{"If-Modified-Since", since}], client) end @spec composite_query(map, client) :: forcex_response def composite_query(body, %Forcex.Client{} = client) do service_endpoint(client, :composite) |> post(body, client) end @spec query(String.t, client) :: forcex_response def query(query, %Forcex.Client{} = client) do base = service_endpoint(client, :query) params = %{"q" => query} |> URI.encode_query "#{base}/?#{params}" |> get(client) end @spec query_all(String.t, client) :: forcex_response def query_all(query, %Forcex.Client{} = client) do base = service_endpoint(client, :queryAll) params = %{"q" => query} |> URI.encode_query "#{base}/?#{params}" |> get(client) end @spec service_endpoint(client, atom) :: String.t defp service_endpoint(%Forcex.Client{services: services}, service) do Map.get(services, service) end defp format_body(""), do: "" defp format_body(body), do: Poison.encode!(body) end