Interface
A number of functions have been added to make it a bit easier to interact with the Airtable API. These are built on top of the low-level interface, which is just a thin wrapper around the HTTP.jl
functions.
Airtable.query
function
If you are interested in retrieving records, your best bet is the Airtable.query
function. Because the airtable API will only return 100 records per request[1], and only allows 5 requests/sec, query()
automatically handles the "paging", pausing for 0.2 seconds in between each request so that you won't hit your limit.
At minimum, query()
requires an AirTable
(note the capital 'T'), which requires that you know the base name and table name for your air table. If you only pass the table, you will retrieve all of the records for that table.
julia> tab = AirTable("Table 1", AirBase("appphImnhJO8AXmmo"))
AirTable("Table 1")
julia> Airtable.query(tab)
3-element Vector{AirRecord}:
AirRecord("recMc1HOSIxQPJyyc", AirTable("Table 1"), (Name = "Record 1", Notes = "Keep this\n", Status = "Todo", Keep = true))
AirRecord("recMwT4P4tKlSLJoH", AirTable("Table 1"), (Name = "Record 2", Notes = "Also keep this", Status = "In progress", Keep = t
rue))
AirRecord("recSStgr3yJnQc2Wg", AirTable("Table 1"), (Name = "Record 3", Status = "Done", Keep = true))
Here, the Credential
is used automatically from the AIRTABLE_KEY
environmental variable. As you can see, unlike the low-level functions that return JSON3.Object
s, query()
returns AirRecord
s
You may also pass additional query parameters (passed as keyword arguments) to filter, or otherwise modify the query.
julia> Airtable.query(tab; filterByFormula="{Status} = 'Todo'")
1-element Vector{AirRecord}:
AirRecord("recMc1HOSIxQPJyyc", AirTable("Table 1"), (Name = "Record 1", Notes = "Keep this\n", Status = "Todo", Keep = true))
julia> Airtable.query(tab; filterByFormula="{Status} != 'Todo'")
2-element Vector{AirRecord}:
AirRecord("recMwT4P4tKlSLJoH", AirTable("Table 1"), (Name = "Record 2", Notes = "Also keep this", Status = "In progress", Keep = t
rue))
AirRecord("recSStgr3yJnQc2Wg", AirTable("Table 1"), (Name = "Record 3", Status = "Done", Keep = true))
For more information about usable query parameters, refer to the airtable documentation.
Airtable.AirBase
— TypeAirBase(id::String)
A wrapper for an Airtable Base, containing its unique identifier. The ID can be identified from the URL of the base (the part right after airtable.com
), or by clicking HELP -> API documentation
from within your base.
Airtable.AirTable
— TypeAirTable(id::String, ::AirBase)
A wrapper for an Airtable Table, containing its unique identifier or name, and parent AirBase
.
Airtable.AirRecord
— TypeAirRecord(id::String, table::AirTable, fields::NamedTuple)
A wrapper for an Airtable Record, containing its unique identifier, parent AirTable
, and values for any stored fields in a NamedTuple.
Typically, you won't crete these on your own, but they will be returned from API queries.
Field values can be accessed using getindex
.
Airtable.query
— FunctionAirtable.query(cred::Credential, baseid, tablename; query_kwargs...)
Shorthand for a "GET" request that handles continuation and rate-limiting.
The Airtable API will return a maximum of 100 records per requests, and only allows 5 requests / sec. This function uses the offset
field returned as part of a requst that does not contain all possible records to make additional requests after pausing 0.21 seconds in between.
Required arguments:
cred
: anAirtable.Credential
containing your API keybaseid
: the endpoint of your Airtable base. See https://airtable.com/api for detailstablename
: the name of the table in your base (eg"Table 1"
)
Query parameters are in the form of keyword arguments, eg filterByFormla = "NOT({Name} = '')", maxRecords=2
. See Airtable API reference for more information.
If you know the exact record id, pass that as a fourth positional argument
AirRecord
s
An AirRecord
refers to a specific row of a specific table. Typically, you would not create records on your own, but they are returned from many of the API functions when you use types from Airtable.jl
(as opposed to the low-level interface just using strings).
AirRecord
s contain fields
, which refer to columns of the table. Any field values that are not set in the table are not included, But they can be accessed using getindex()
.
julia> rec = first(Airtable.query(tab))
AirRecord("recMc1HOSIxQPJyyc", AirTable("Table 1"), (Name = "Record 1", Notes = "Keep this\n", Status = "Todo", Keep = true))
julia> rec[:Name]
"Record 1"
julia> rec[:Status]
"Todo"
Adding or changing records
You can add or update records using Airtable.post!
and Airtable.patch!
respectively. Using post!
requires an AirTable
as the first argument, while patch!
requires an AirRecord
.
Using post!
To use post!
, pass a table and a NamedTuple
with the fields that you want to add. Note that if the fields don't already exist in the parent table, this will throw an error.
julia> new_rec = Airtable.post!(tab, (; Name = "Some Record", Notes = "It's a nice record"))
AirRecord("recYvPIayZx1okJ41", AirTable("Table 1"), (Name = "Some Record", Notes = "It's a nice record"))
Notice that the return value is an AirRecord
. It can be useful to hold onto this, since it contains the unique identifier. You can also pass a vector of NamedTuple
s to create multiple records (post!
will automatically limit 10 records at a time, in compliance with the Airtable API).
See the note about rate limits.
Using patch!
If you want to update an existing record, use patch!
, with an AirRecord
as the first argument, and a NamedTuple
for the fields you want to change.
julia> Airtable.patch!(new_rec, (; Status="Done", Notes="It *was* a nice record"))
AirRecord("recYvPIayZx1okJ41", AirTable("Table 1"), (Name = "Some Record", Notes = "It *was* a nice record", Status = "Done"))
Any fields that you don't include will remain the same. If you want to clear a field, pass missing
julia> Airtable.patch!(new_rec, (; Status="Done", Notes=missing))
AirRecord("recYvPIayZx1okJ41", AirTable("Table 1"), (Name = "Some Record", Status = "Done"))
You can also pass a vector of AirRecords
along with an equal-length vector of NamedTuple
s to patch multiple records at once (patch!
will automatically limit to 10 records at a time, in compliance with the Airtable API).
Using delete!
To remove a record, simply pass an AirRecord
with the same id
to delete!
.
julia> Airtable.delete!(new_rec)
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 2 entries:
:deleted => true
:id => "recYvPIayZx1okJ41"
A note on rate limits
Airtable.com only allows 5 requests / sec. All functions that make requests will pause if more than 5 requests have been made in the previous second.
Functions and Types
Missing docstring for AirBase
. Check Documenter's build log for details.
Missing docstring for AirTable
. Check Documenter's build log for details.
Missing docstring for AirRecord
. Check Documenter's build log for details.
Missing docstring for Airtable.query
. Check Documenter's build log for details.
Airtable.post!
— FunctionAirtable.post!(cred::Credential, path[, headers=[], body=nothing]; query_kwargs...)
Shorthand for Airtable.request("POST", cred, path[, headers, body]; query_kwargs)
Airtable.patch!
— FunctionAirtable.patch!(cred::Credential, path[, headers=[], body=nothing]; query_kwargs...)
Shorthand for Airtable.request("PATCH", cred, path[, headers, body]; query_kwargs)
Airtable.delete!
— FunctionAirtable.delete!(cred::Credential, path[, headers=[], body=nothing]; query_kwargs...)
Shorthand for Airtable.request("DELETE", cred, path[, headers, body]; query_kwargs)
- 1This is the default, you can change this with the
pageSize
parameter, but 100 is the maximum.