How to hook emacs up to a json service?

Emacs has pretty good built-in support for this kind of thing, at least at the basic level of making requests and parsing responses. Use url-retrieve or url-retrieve-synchronously to fetch data from a remote service. As the names suggest, one is an asynchronous call which takes a callback, the other a blocking call which returns a buffer containing the response. Load them by including (require 'url) in your Elisp file.

The url- functions are documented in a separate Info manual from the rest of Elisp, named "URL", but some useful features go unmentioned there. For GET requests where arguments are passed in the URL, the url-build-query-string function is useful for constructing a string of query parameters from an a-list of keys and values. For POST, PUT, DELETE and other requests, you may need to let-bind the variables url-request-data, url-request-method and url-request-extra-headers. They have informative docstrings.

A final confusing thing about using these calls for HTTP URLs is that they leave the HTTP response headers in the same buffer as the response body, which may not be what you expect. A simple way to deal with this is to use the (undocumented) url-http-end-of-headers variable to skip over the headers before processing the body, though I suspect there might be better ways.

Use the json-read function to parse JSON responses, and bind the variables json-array-type, json-object-type, and json-key-type to control how JSON types are converted to Lisp types. This function is obtained by including (require 'json). XML responses can be parsed using xml-parse-region or libxml-xml-parse-region. The latter requires Emacs to be compiled with libxml support, the former is implemented in Elisp.

Putting this together, the skeleton of a request to a JSON service looks something like this:

(url-retrieve
 "http://example.com/api/some/request"
 (lambda (events)
   (goto-char url-http-end-of-headers)
   (let ((json-object-type 'plist)
         (json-key-type 'symbol)
         (json-array-type 'vector))
     (let ((result (json-read)))
       ;; Do something with RESULT here
       ))))

In the callback, you can work with result like any other Lisp value. The plist-get, pcase and cl-destructuring-bind functions are often useful for extracting pieces of the result. Use (require 'pcase) to get the pcase macro, (require 'cl-lib) to get cl-destructuring-bind.


This is what I use to lookup currency exchange rates from a json webservice at rate-exchange.appspot.com:

(defun my-json-get (url)
  (interactive)
  (progn
    (require 'json)
    (with-current-buffer (url-retrieve-synchronously url)
      (goto-char (point-min))
      (re-search-forward "^$")
      (json-read))))
(defun my-currency-exchange-rate (from to)
  (let ((xurl (format "http://rate-exchange.appspot.com/currency?from=%s&to=%s" from to)))
    (assoc-default 'rate (my-json-get xurl))))

Example usage:

(my-currency-exchange-rate "USD" "SEK")