For developers: easily use IDs instead of names

After a good bit of time of developing scripts in Airtable, two things began jumping out at me when starting any new scripting project:

  • I got tired of manually making arrays of field names when querying a table, and needing to keep that list current as development progressed.
  • I got tired of thinking about possibly-broken code if table, field, or view names were to change in the future.

As a result, I wrote a script to help with both of those issues. It’s gone through a few iterations, and it’s now at a point where I’m ready to share it with others. Eventually it’ll likely become a custom extension, but the script version is working quite well for now.

Get Table IDs

While the title makes it feel like it’s focused on table IDs, it’s really about getting ALL of the IDs tied to a table, including its fields and views. In other words, this script makes it a lot easier to use IDs instead of names for tables, fields, and views in your code, whether you’re working in Airtable’s scripting environments—the Scripting extension or an automation script action—or building a custom extension.

What it does

When you run the script after adjusting its settings, it generates boilerplate code based on the currently-active table. Using the script settings, you can control:

  • Whether it outputs helper objects for fields and/or views
  • Whether the code should be styled for an Airtable script environment or a custom extension
  • What indentation size to use (2 or 4 spaces)

Examples

Here’s what the output looks like on a default new table. Field and view output are both turned on, it’s set to generate code for an Airtable script, and indentation is set to 2 spaces.

const TB = {
  sampleTable: "tblarZU8IJ6RmtqVy",
}

const FL = {
  sampleTable: {
    assignee: "fldhsGLJ5aJX9zw6C",
    name: "fldQNfTyKjLAVxMt6",
    notes: "fldt7Vxq3C3W0S1un",
    status: "fld9VjUVHPLQxTSF1",
  },
}

const VW = {
  sampleTable: {
    gridView: "viwv5CYAmRIW30iz1",
  },
}

const sampleTableTable = base.getTable(TB.sampleTable)
const sampleTableQuery = await sampleTableTable.selectRecordsAsync({fields: Object.values(FL.sampleTable)})

After defining three helper objects—TB for tables, FL for fields, and VW for views—it creates a variable for the table reference by default, along with a query for that table based on the fields listed in the FL object. If I don’t need all of those fields, it’s fairly easy to cut out the references I don’t need from the FL object. The query line doesn’t need to be touched because it takes whatever’s available in that object.

To use a field reference when getting a cell value from an object, the syntax would look like this:

const assignee = record.getCellValue(FL.sampleTable.assignee)

The FL object can also be used when referring to a field for record creation or updating.

await myTable.updateRecordAsync(recordId, {
  [FL.myTable.firstName]: newFirstName,
  [FL.myTable.lastName]: newLastName
})

While FL.sampleTable.assignee is longer than just referring to the field by "Assignee", I’ve come to
appreciate the fact that this structure still lets me use a form of the field name, plus I see the connection between the field and the table where it resides. I also have the security of knowing that table, field, or view name changes won’t break anything.

If I change the appropriate script setting to output code for a custom extension, it looks like this next sample.

import { base } from '@airtable/blocks'

const TB = {
  sampleTable: base.getTableIfExists("tblarZU8IJ6RmtqVy"),
}

const FL = {
  sampleTable: {
    assignee: TB.sampleTable.getFieldIfExists("fldhsGLJ5aJX9zw6C"),
    name: TB.sampleTable.getFieldIfExists("fldQNfTyKjLAVxMt6"),
    notes: TB.sampleTable.getFieldIfExists("fldt7Vxq3C3W0S1un"),
    status: TB.sampleTable.getFieldIfExists("fld9VjUVHPLQxTSF1"),
  },
}

In this case, you have actual table and field instances and not just IDs, but they’re still built based on IDs for greater stability.

In many cases I’m using fields from multiple tables. Here’s a longer generic example where I’ve taken the output from one table and merged it with the output from another table. This merging process is manual, but it’s not that difficult. (In the future extension version, I hope to automate this process.)

const TB = {
  myTable: "tblAAAAAAAAAAAAAA",
  nutherTable: "tblBBBBBBBBBBBBBB",
}

const FL = {
  myTable: {
    firstName: "fldXXXXXXXXXXXXXX",
    lastName: "fldYYYYYYYYYYYYYY",
    name: "fldZZZZZZZZZZZZZZ",
  },
  nutherTable: {
    firstField: "fldGGGGGGGGGGGGGG",
    secondField: "fldHHHHHHHHHHHHHH",
    thirdField: "fldIIIIIIIIIIIIII",
  },
}

Download

You can find this script as the first addition to a public GitHub repository where I plan on sharing the many free scripts that I’ve developed. The docs in the repo contain a bit more info on its design as well.

That’s a wrap

This system I’ve come up with might not work for everyone, but it works extremely well for me, and I use it all the time. It helps to accelerate the initial stages of Airtable script development and gives me increased peace of mind. If you don’t feel like it’s a good fit, perhaps it can at least inspire you to rethink your own development processes and come up with a solution that works for you.

6 Likes