This is an up to date wrapper for the Salesforce.com REST API. I initially found working with the API to be a bit frustrating and hopefully this wrapper will make everything easy for you.
More information about the Salesforce REST API can be found at
http://www.salesforce.com/us/developer/docs/api_rest/
It is available from Clojars. : )
[] (https://clojars.org/org.clojars.zugnush/salesforce)
We first need to set up some authentication information as a Clojure map. All the information can be found in your Salesforce account.
In order to get an auth token and information about your account we call the auth! function like this
(use 'salesforce.core)
(def config
{:client-id ""
:client-secret ""
:username ""
:password ""
:security-token ""})
(def auth-info (auth! config))
This returns a map of information about your account including an authorization token that will allow you to make requests to the REST API.
The response looks something like this
{:id "https://login.salesforce.com/id/1234",
:issued_at "1367488271359",
:instance_url "https://na15.salesforce.com",
:signature "1234",
:access_token "1234"}
Now you can use your auth-config to make requests to the API.
(resources auth-info)
There are multiple versions of the Salesforce API so you need to decare the version you want to use.
You can easily get the latest API version with the following function
(latest-version) ;; => "27.0"
You can set a version in several ways.
Globally
(set-version! "27.0")
Inside a macro
(with-version "27.0"
;; Do stuff here )
Or just using the latest version (this is slow as it needs to make an additional http request)
(with-latest-version
;; Do stuff here)
The following methods are available
Get all sobjects
(so->objects auth-info)
Get all records
(so->all "Account" auth-info)
Get recently created items
(so->recent "Account" auth-info)
Get a single record
;; Fetch all the info
(so->get "Account" "001i0000007nAs3" nil auth-info)
;; Fetch only the name and website attributes
(so->get "Account" "001i0000007nAs3" ["Name" "Website"] auth-info))
;; Fetch using external id field
(so->get "Account" {:ext_field "123"} nil auth-info)
Create a record
(so->create "Account" {:Name "My Account"} auth-info)
Upsert a record
(so->update "Account" {:Name "My Updated Account "} "001i0000008Ge2OAAS" auth-info)
;; upsert using external id field
(so->update "Account" {:Name "My Updated Account "} {:ext_field "123"} auth-info)
Delete a record
(so->delete "Account" "001i0000008Ge2OAAS" auth-info)
Describe an record
(so->describe "Account" auth-info)
Salesforce provides a query language called SOQL that lets you run custom queries on the API.
(soql "SELECT name from Account" auth-info)
This example shows an example REPL session using the API
(def config
{:client-id ""
:client-secret ""
:username ""
:password ""
:security-token ""})
;; Get auth info needed to make http requests
(def auth (auth! config))
;; Get and then set the latest API version globally
(set-version! (latest-version))
;; Now we are all set to access the salesforce API
(so->objects auth)
;; Get all information from accounts
(so->all "Account" auth)
;; Fetch a single account
(so->get "Account" "001i0000008Ge2TAAS" auth)
;; Create a new account
(so->create "Account" {:Name "My new account"} auth)
;; Delete the account we just created
(so->delete "Account" "001i0000008JTPpAAO" auth)
;; Finally use SOQL to find account information
(:records (soql "SELECT name from Account" auth))
This final example shows how to use bulk 2.0 API functionality Proper control on really large uploads not implemented yet
(def config
{:client-id ""
:client-secret ""
:username ""
:password ""
:security-token ""})
;; Get auth info needed to make http requests
(def auth (auth! config))
;; Get and then set the latest API version globally
(set-version! (latest-version))
;; List all jobs
(bulk-get-all-jobs auth {})
=>
{:done true,
:records
[{:createdById "0057F000002HogPQAS",
:operation "insert",
:lineEnding "LF",
:state "JobComplete",
:systemModstamp "2018-05-28T03:51:00.000+0000",
:concurrencyMode "Parallel",
:id "7507F000004pUAxQAM",
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-28T03:47:41.000+0000",
:columnDelimiter "COMMA",
:jobType "V2Ingest",
:object "Contact"}
{:createdById "0057F000002HogPQAS",
:operation "insert",
:lineEnding "LF",
:state "JobComplete",
:systemModstamp "2018-05-28T04:12:12.000+0000",
:concurrencyMode "Parallel",
:id "7507F000004pUN8QAM",
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-28T04:10:02.000+0000",
:columnDelimiter "COMMA",
:jobType "V2Ingest",
:object "Contact"}
{:createdById "0057F000002HogPQAS",
:operation "insert",
:lineEnding "LF",
:state "Aborted",
:systemModstamp "2018-05-29T03:33:15.000+0000",
:concurrencyMode "Parallel",
:id
"7507F000004pUYWQA2",
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-28T04:43:01.000+0000",
:columnDelimiter "COMMA",
:jobType "V2Ingest",
:object "Contact"}
{:createdById "0057F000002HogPQAS",
:operation "insert",
:lineEnding "LF",
:state "Open",
:systemModstamp "2018-05-29T03:47:24.000+0000",
:concurrencyMode "Parallel",
:contentUrl
"services/data/v42.0/jobs/ingest/7507F000004peFEQAY/batches",
:id "7507F000004peFEQAY",
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-29T03:47:24.000+0000",
:columnDelimiter "COMMA",
:jobType "V2Ingest",
:object "Contact"}],
:nextRecordsUrl nil}
;; Create a job
(def job (bulk-insert-job auth "Contact" {:columnDelimiter \,}))
; other options available, check spec and clj->sf option mapping
job =>
{:createdById "0057F000002HogPQAS",
:operation "insert",
:lineEnding "LF",
:state "Open",
:systemModstamp "2018-05-29T22:35:44.000+0000",
:concurrencyMode "Parallel",
:contentUrl
"services/data/v42.0/jobs/ingest/7507F000004pljMQAQ/batches",
:id "7507F000004pljMQAQ",
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-29T22:35:44.000+0000",
:columnDelimiter "COMMA",
:object "Contact"}
;; Check it's status
(bulk-job-info auth job)
;; =>
{:apexProcessingTime 0,
:totalProcessingTime 0,
:createdById "0057F000002HogPQAS",
:retries 0,
:operation "insert",
:lineEnding "LF",
:state "Open",
:systemModstamp "2018-05-29T22:35:44.000+0000",
:concurrencyMode "Parallel",
:contentUrl
"services/data/v42.0/jobs/ingest/7507F000004pljMQAQ/batches",
:id "7507F000004pljMQAQ",
:apiActiveProcessingTime 0,
:contentType "CSV",
:apiVersion 42.0,
:createdDate "2018-05-29T22:35:44.000+0000",
:columnDelimiter "COMMA",
:jobType "V2Ingest",
:object "Contact"}
;; Upload a csv
(def csvdata
(csv/write-csv
(maps->valvec
[{:FirstName "Hans" :LastName "Solo"}
{:FirstName "Jabba" :LastName "Hutt"}])))
(bulk-upload-job-data auth job csvdata)
;; Close the job
(bulk-close-job auth job)
;; wait a minute
(bulk-job-info auth job)
;; => {:apexProcessingTime 0, :totalProcessingTime 485, :createdById "0057F000002HogPQAS", :retries 0, :operation "insert", :lineEnding "LF", :state "JobComplete", :systemModstamp "2018-05-30T03:52:33.000+0000", :concurrencyMode "Parallel", :numberRecordsFailed 0, :id "7507F000004poJGQAY", :numberRecordsProcessed 2, :apiActiveProcessingTime 83, :contentType "CSV", :apiVersion 42.0, :createdDate "2018-05-30T03:52:16.000+0000", :columnDelimiter "COMMA", :jobType "V2Ingest", :object "Contact"}
;; Fetch successful results
(bulk-job-result-by-status auth job :success)
;; #{:success :failed :unprocessed}
=>
"\"sf__Id\",\"sf__Created\",FirstName,LastName\n\"0037F00000eDOAzQAO\",\"true\",\"Hans\",\"Solo\"\n\"0037F00000eDOB0QAO\",\"true\",\"Jabba\",\"Hutt\"\n"
;; Fetch failed results
Bulk options mapping The following map transform clojure keyword options to SF api 2.0 option string values
(def clj->sf
{:createjob
{:lineEnding {:lf "LF", :crlf "CRLF"},
:contentType {:csv "CSV"},
:columnDelimiter
{\' "QUOTE",
\; "SEMICOLON",
\, "COMMA",
\| "PIPE",
\t "TAB",
\^ "CARET"},
:operation
{:insert "insert",
:upsert "upsert",
:update "update",
:delete "delete"}},
:closejob
{:state {:upload-complete "UploadComplete", :aborted "Aborted"}},
:alljobs
{:concurrencyMode {:parallel "Parallel", :serial "Serial"},
:isPkChunkingEnabled {:true "true", :false "false"},
:jobType
{:big "BigObjectIngest", :classic "Classic", :v2 "V2Ingest"}},
:jobstatus
{:success "successfulResults/",
:failed "failedResults/",
:unprocessed "unprocessedrecords/"}})
Distributed under the Eclipse Public License, the same as Clojure.
Can you improve this documentation? These fine people already did:
owain lewis, garethdavies, Owain Lewis, Neil.McCallum, taffowl & Andrew JonesEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close