Emacs and MS Graph

OK, so in the prior post we discussed how to run a program asynchronously, and in particular how to call into our powershell script.

Today we're going to put everything together into a proper package we can use.

Preamble

Let's create a file in ~/mymsgraph.el. We'll be able to load this file as we prototype with load-file interactively.

We'll start with a good top banner:

;;; mymsgraph.el --- Functions for Microsoft Graph API access -*- lexical-binding: t; -*-

Reading Data

Next, let's add a more heavily parameterized version of what we had before. Note that I'm still hard-coding the scopes here, which is something you'll probably want to have callers pass in.

(defun mymsgraph-read-url (url callback)
  "Reads a URL from the Microsoft Graph API and calls back with a parsed JSON object."
  (let ((scopes "user.read openid profile offline_access"))
    (setq myproc (start-process "graphmacs" nil "powershell.exe" "-NoLogo" "-NonInteractive" "-ExecutionPolicy" "Bypass" "-File" (expand-file-name "~/graphmacs.ps1")))
    (setq result "")
    (set-process-filter myproc
                        (lambda (process output)
                          (progn
                            (setq result (concat result output)))))
    (set-process-sentinel myproc
                          (lambda (process event)
                            (if (string-equal event "finished\n")
                                (progn
                                  (message "%s: %s" event result)
                                  (string-match "\\({.@odata.+\\)" result)
                                  (setq odata (match-string 1 result))
                                  (setq jresult (json-parse-string odata))
                                  (funcall callback jresult)
                                  ))))))

Basically, this is the kind of transform you do bit by bit when you're building something interactively this way. You can start with some hard-coded values for a specific case, then gradually make it more broadly usable and generic by parameterizing the behavior of your code.

Useful Functions

Now, we can actually put this into a more directly usable function, to do lookups on our contacts and display them in the active buffer. The first function here formats and inserts a result, and the second one is an interactive function that prompts for a display name, does the lookup, and calls our first function (via the callback parameter in mymsgraph-read-url).

(defun mymsgraph-insert-user-lookup-results (jresult)
  "Inserts a name and email representation from the given OData result."
  (insert (format "%s (%s) %s" (gethash "displayName" jresult) (gethash "mail" jresult) (gethash "mobilePhone" jresult))))

(defun mymsgraph-insert-user-lookup (display-prefix)
  "Inserts user information for for the given display prefix"
  (interactive "sDisplay name prefix: ")
  (mymsgraph-read-url (format "https://graph.microsoft.com/v1.0/me/contacts?$filter=startswith(displayName,'%s')" display-prefix) 'mymsgraph-insert-user-lookup-results))

A few important things to note:

Finishing Touches

Finally, we'll end by declaring that we provide the mymsgraph API.

(provide 'mymsgraph)

Now, when you load the package, you can run M-x mymsgraph-insert-user-lookup, type in a name, and have it be looked up for you!

Happy MS Graph querying!

Tags:  codingemacs

Home