API Spelunking with Org Babel
Occasionally I need to interact with an API and store their responses. For that
ob-shell+curl does the job. Every now the responses are large enough that I
need massage them with jq. That's where I use ob-jq. Recently I had to look
for id of the latest fedora image Hetzner provides. Using that as an example
I'll show how can one use ob-shell & ob-jq to explore JSON API responses.
You may be asking why use ob-shell+curl when there other packages like
ob-restclient, walkman, etc. Shelling out to curl has the advantage of being
easy to share the invocation with ~~infidels~~non-emacs users.
Encrypting the token
First a detour on storing credentials. APIs usually require a credential. We
should shouldn't store any authentication token in plain text. Emacs provides
auth-source to retrieve your secrets. auth-source can fetch the data from
any number of sources, including your system's keyring. I prefer to store API
tokens in an encrypted file, ~/.authinfo.gpg, which is encrypted using GPG.
Each entry in the autinfo file should conform to the following format:
machine api.hetzner.cloud password 🎩t0psecret🎩
We can retrieve the token with the following invocation
(auth-source-pick-first-password :host "api.hetzner.cloud")
By using the :var header argument. This will let us bind an environment
variable to the value of an elisp expression. All together now:
#+name: list-system-images.json
#+begin_src shell :var token=(auth-source-pick-first-password :host "api.hetzner.cloud") :results output
curl -H "Authorization: Bearer $token" "https://api.hetzner.cloud/v1/images?type=system"
#+end_src
Note that we gave a name to the src block. This is important so that we can refer to its output in another src block.
Massaging the response using jq
The API retrieves a lot of fields which are of little interest to me. So I can use jq-mode's org-babel integration to do so.
#+begin_src jq :stdin list-system-images.json
.images[] | select(.name | match("fedora")) | pick(.id, .name, .os_flavor, .os_version)
#+end_src
Next steps
Note that although the example it can be used for commands that output a large
amount JSON, like cargo-metadata.