- Published on
Making SOQL Queries from Emacs
- Authors
- Name
- Bryan Thode
Need to make a SOQL query, but hate leaving Emacs?
Prerequisites
Request
While raw curl calls as entirely possible to do from Emacs, the request package makes this much easier.
After using whatever package manager of your liking to download it, let's ensure it's loaded.
(require 'request)
Connected App
A username and password isn't enough to request a token programmatically, so we're going to need to create a Connected App.
Log in as an organization administrator, and assuming you're in the Lightning UI.
- Setup > Apps > App Manager > New Connected App
- Enable OAuth settings, Device Flow, and give full OAuth scopes
- Obtain the Consumer Key and Secret from Consumer Details
Assign the variables required for our request
Now that we have our Consumer Key and Secret, we're mostly there. Provided below is a org-babel source block to assign all the required variables for our subsequent request.
#+begin_src emacs-lisp
(setq sfdc.orgid "00D************")
(setq sfdc.loginurl "https://*****************.salesforce.com/")
(setq sfdc.url "https://***********************.lightning.force.com/")
(setq sfdc.casecret "********")
(setq sfdc.cakey "********")
(setq sfdc.username "my@user.com")
(setq sfdc.password "*********")
#+end_src
sfdc.loginurl
is the instance url of your Salesforce org, and sfdc.url
is the My Domain url.
Once you've updated the values in accordance with your org, evaluate the source block.
Requesting the token
We're ready to request our token. You can either evaluate this org-babel code block or otherwise make the refresh-token
functional available to Emacs.
#+begin_src emacs-lisp
(defun refresh-token ()
"Obtain a current Salesforce session id token"
(request (concatenate 'string sfdc.loginurl "/services/oauth2/token")
:type "POST"
:params `(("client_id" . ,sfdc.cakey) ("client_secret" . ,sfdc.casecret) ("username" . ,sfdc.username) ("password" . ,sfdc.password) (grant_type . "password") )
:parser 'json-read
:sync t
:success (cl-function
(lambda (&key data &allow-other-keys)
(setq sfdc.token (assoc-default 'access_token data)
)))))
#+end_src
Finally execute refresh-token
and ensure sfdc.token is now defined. (describe-variable
)
SOQL Query
We're finally ready to use our token to execute a SOQL query.
I'm determining the latest api version of the Salesforce instance from /services/data, and then make a SOQL query against it. An error code of 401 should call refresh-token, so while your request may fail with an expired token, you can just rerun it.
#+begin_src emacs-lisp :results verbatim :wrap src json
(request (concatenate 'string sfdc.loginurl "/services/data")
:parser 'json-read
:sync t
:success (cl-function
(lambda (&key data &allow-other-keys)
( setq sfdc.endpoint (concatenate 'string sfdc.loginurl (cdr (assoc 'url (elt (reverse data) 0 ))))))))
(defun sfdc-query(query)
(setq sfdc.auth (concatenate 'string "Bearer " sfdc.token ))
(request-response-data (request (concatenate 'string sfdc.endpoint "/query")
:type "GET"
:headers `( ("Content-Type" . "application/json") (grant_type . "password") ("Authorization" . ,sfdc.auth ) )
:params `(("q" . ,query) )
:parser 'json-read
:sync t
:success (cl-function
(lambda (&key data &allow-other-keys)
(print (assoc-default `records data))))
:status-code '((401 . (lambda (&rest _) (refresh-token)))))))
(sfdc-query "select id from contact limit 10")
#+end_src
