Skip to content

Instantly share code, notes, and snippets.

@martinklepsch
Last active November 26, 2023 20:36
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinklepsch/302121cdacd6771354c6 to your computer and use it in GitHub Desktop.
Save martinklepsch/302121cdacd6771354c6 to your computer and use it in GitHub Desktop.
A minimal Clojure client for Airtable.com's HTTP API.
(ns oxygen.client
"A minimal Clojure client for Airtable.com's HTTP API.
Supports retrieval of whole tables as well as individual records.
Dependencies: [org.clojure/data.json \"0.2.6\"] [clj-http \"2.0.0\"]"
(:require [clojure.data.json :as json]
[clojure.string :as string]
[clojure.set :as set]
[clj-http.client :as client]))
(def api-base "https://api.airtable.com/v0")
(defn build-request-uri [base-id resource-path]
(string/join "/" (concat [api-base (name base-id)] (map name resource-path))))
(defn get-in-base*
[{:keys [api-key base-id] :as base} resource-path]
(let [req-uri (build-request-uri base-id resource-path)]
(client/get req-uri {:headers {"Authorization" (str "Bearer " api-key)}})))
(defn ^:private kwdize [m]
(set/rename-keys m {"id" :id "fields" :fields "createdTime" :created-time}))
(defn validate-base [{:keys [api-key base-id] :as base}]
(assert api-key ":api-key must present in passed credentials")
(assert base-id ":base-id must present in passed credentials"))
(defn validate-resource-path [resource-path]
(assert (sequential? resource-path) "resource-path must be a sequence")
(assert (<= (count resource-path) 2) "resource-path can't have more than two items"))
(defn get-in-base
"Retrieve tables and records from a table.
`base` needs to be a map containing `:api-key` and `:base-id`.
`resource-path` must be a sequence containing the table name
and an optional record id.
`:base-id` and elements in `resource-path` can be strings or keywords."
[base resource-path]
(validate-base base)
(validate-resource-path resource-path)
(let [data (-> (get-in-base* base resource-path) :body json/read-str)]
(if (= (count resource-path) 1)
(map kwdize (get data "records"))
(kwdize data))))
(comment
(def my-base {:api-key "keyXXXXXXXXXXXXXX"
:base-id "appXXXXXXXXXXXXXX"})
;; Retrieve a single record
(get-in-base my-base ["companies" "recXXXXXXXXXXXXXX"])
;; Retrieve a full table
(get-in-base my-base ["products"]))
@shegeley
Copy link

Don't you mind If i'd take this code, add other CRUD methods and post on clojars as package?

@martinklepsch
Copy link
Author

It’s all yours :)

@shegeley
Copy link

Thanks. I already forked the other repo and changed it a little. Also added to Clojure repo. https://github.com/altjsus/airtable-clj

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment