module Airtable.Query
( module Airtable.Table
, AirtableOptions(..)
, defaultAirtableOptions
, airtableOptionsToWreqOptions
, tableNameToUrl
, getRecords
, createRecord
, updateRecord
, deleteRecord
) where
import Airtable.Table
import GHC.Stack
import Network.Wreq
import Control.Lens ((^.), (.~), (&))
import Control.Monad (void)
import Data.Aeson (FromJSON, ToJSON, eitherDecode, toJSON)
import Data.Monoid
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Char8 as BC
data AirtableOptions = AirtableOptions {
apiKey :: String
, appId :: String
, apiVersion :: Int
}
defaultAirtableOptions :: AirtableOptions
defaultAirtableOptions = AirtableOptions {
apiKey = ""
, appId = ""
, apiVersion = 0
}
base_url :: String
base_url = "https://api.airtable.com/"
airtableOptionsToWreqOptions :: AirtableOptions -> Options
airtableOptionsToWreqOptions opts =
defaults & header "Authorization" .~ ["Bearer " <> BC.pack (apiKey opts)]
tableNameToUrl :: AirtableOptions -> TableName -> String
tableNameToUrl opts tname =
base_url
<> "v"
<> show (apiVersion opts)
<> "/"
<> appId opts
<> "/"
<> tname
fromResp :: (HasCallStack, FromJSON a) => Response ByteString -> a
fromResp r = decoder $ r ^. responseBody
where
decoder b = case eitherDecode b of
Left e -> error e
Right r -> r
getRecords :: (HasCallStack, FromJSON a) => AirtableOptions -> TableName -> IO (Table a)
getRecords opts tname =
getRecordsFromUrl (airtableOptionsToWreqOptions opts) (tableNameToUrl opts tname)
getRecordsFromUrl :: (HasCallStack, FromJSON a) => Options -> String -> IO (Table a)
getRecordsFromUrl opts url = do
resp <- getWith opts url
getMore (fromResp resp)
where
getMore tbl = case tableOffset tbl of
Just offset -> do
resp <- getWith (opts & param "offset" .~ [offset]) url
getMore $ fromResp resp <> tbl
Nothing ->
pure tbl
createRecord :: (HasCallStack, ToJSON a, FromJSON a) => AirtableOptions -> TableName -> a -> IO (Record a)
createRecord opts tname a = do
resp <- postWith netOpts url payload
return $ fromResp resp
where
url = tableNameToUrl opts tname
netOpts = airtableOptionsToWreqOptions opts
payload = toJSON a
updateRecord :: (ToJSON a) => AirtableOptions -> TableName -> RecordID -> a -> IO ()
updateRecord opts tname recId a = do
void $
customPayloadMethodWith "PATCH" netOpts url payload
where
url = tableNameToUrl opts tname <> "/" <> rec2str recId
netOpts = airtableOptionsToWreqOptions opts
payload = toJSON a
deleteRecord :: AirtableOptions -> TableName -> RecordID -> IO ()
deleteRecord opts tname recId =
void $ deleteWith netOpts url
where
netOpts = airtableOptionsToWreqOptions opts
url = tableNameToUrl opts tname <> "/" <> rec2str recId