forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			193 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			193 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | --- | ||
|  | title: Airtable | ||
|  | pagination_prev: demos/static/index | ||
|  | pagination_next: demos/cli | ||
|  | --- | ||
|  | 
 | ||
|  | At the time of writing (2023 February 15), Airtable recommends Personal Access | ||
|  | Tokens for interacting with the official API. | ||
|  | 
 | ||
|  | ## NodeJS Integration
 | ||
|  | 
 | ||
|  | The main module is `airtable` and can be installed with `npm`: | ||
|  | 
 | ||
|  | ```bash | ||
|  | npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz airtable | ||
|  | ``` | ||
|  | 
 | ||
|  | To obtain a reference to a table, code needs a [PAT](#personal-access-token), | ||
|  | the name of the workspace (typically starting with `app`), and the name of the | ||
|  | desired table (the Excel import typically supports the worksheet name): | ||
|  | 
 | ||
|  | ```js | ||
|  | const Airtable = require("airtable"), XLSX = require("xlsx"); | ||
|  | /* query all records in a table */ | ||
|  | const conn = new Airtable({apiKey: "PAT...", /* and other options ... */}); | ||
|  | const table = conn.base("app...").table("tablename..."); | ||
|  | ``` | ||
|  | 
 | ||
|  | ### Exporting Data
 | ||
|  | 
 | ||
|  | When querying data, a result set will be a simple array of Record objects. The | ||
|  | `fields` property is a simple JS object compatible with `json_to_sheet`: | ||
|  | 
 | ||
|  | ```js | ||
|  | /** Create SheetJS worksheet from Airtable table */ | ||
|  | async function airtable_to_worksheet(table) { | ||
|  |   /* get all rows */ | ||
|  |   const result = await table.select().all(); | ||
|  | 
 | ||
|  |   /* pull raw objects from the result */ | ||
|  |   // highlight-next-line | ||
|  |   const aoo = result.map(r => r.fields); | ||
|  | 
 | ||
|  |   /* create a worksheet */ | ||
|  |   const worksheet = XLSX.utils.json_to_sheet(aoo); | ||
|  |   return worksheet; | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | :::caution | ||
|  | 
 | ||
|  | The results are not guaranteed to be sorted.  The official API includes options | ||
|  | for sorting by fields. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | ### Importing Data
 | ||
|  | 
 | ||
|  | When inserting records, each object should be wrapped in a parent object with a | ||
|  | single `fields` property: | ||
|  | 
 | ||
|  | ```js | ||
|  | /** Append records from a SheetJS worksheet to Airtable table */ | ||
|  | async function airtable_load_worksheet(table, worksheet) { | ||
|  |   /* suppose the field names */ | ||
|  |   const aoo = XLSX.utils.sheet_to_json(worksheet); | ||
|  | 
 | ||
|  |   /* reshape to be compatible with Airtable API */ | ||
|  |   // highlight-next-line | ||
|  |   const airtable_rows = aoo.map(fields => ({ fields })); | ||
|  | 
 | ||
|  |   /* upload data */ | ||
|  |   return await table.create(airtable_rows); | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Complete Example
 | ||
|  | 
 | ||
|  | 0) Create a free Airtable account. | ||
|  | 
 | ||
|  | ### Personal Access Token
 | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | In the past, Airtable offered API keys.  They are slated to deprecate API keys | ||
|  | in January 2024. They recommend "Personal Access Tokens" for operations. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | API actions will require a PAT, which must be created through the developer hub: | ||
|  | 
 | ||
|  | 1) Click on account icon (topright area of the page) and select "Developer Hub". | ||
|  | 
 | ||
|  | 2) Click "Create Token". | ||
|  | 
 | ||
|  | 3) In the form, make the following selections: | ||
|  | 
 | ||
|  | - Name: enter any name (for example, "SheetJS Test") | ||
|  | - Scopes: `data.records:read` and `data.records:write` (adding 2 scopes) | ||
|  | - Access: "All current and future bases in all current and future workspaces" | ||
|  | 
 | ||
|  | The form will look like the screenshot below: | ||
|  | 
 | ||
|  |  | ||
|  | 
 | ||
|  | 4) Click "Create Token" and you will see a popup.  Copy the token and save it. | ||
|  | 
 | ||
|  | ### Workspace
 | ||
|  | 
 | ||
|  | For the purposes of this demo, a sample workspace should be created: | ||
|  | 
 | ||
|  | 5) Download <https://sheetjs.com/pres.xlsx> | ||
|  | 
 | ||
|  | 6) Create a project in Airtable using "Quickly upload". Select "Microsoft Excel" | ||
|  | and select the downloaded file from step 1.  Click "Upload", then "Import". | ||
|  | 
 | ||
|  | 7) A workspace will be created. The name will be found in the URL. For example: | ||
|  | 
 | ||
|  | ``` | ||
|  | https://airtable.com/appblahblah/tblblahblah/blahblah | ||
|  | --------------------/^^^^^^^^^^^/ workspace name | ||
|  | ``` | ||
|  | 
 | ||
|  | the first part after the `.com` will be the workspace name. | ||
|  | 
 | ||
|  | ### Exporting Data
 | ||
|  | 
 | ||
|  | 8) Save the following to `read.js`: | ||
|  | 
 | ||
|  | ```js title="read.js" | ||
|  | const Airtable = require("airtable"), XLSX = require("xlsx"); | ||
|  | // highlight-start | ||
|  | /* replace the value with the personal access token */ | ||
|  | const apiKey = "pat..."; | ||
|  | /* replace the value with the workspace name */ | ||
|  | const base = "app..."; | ||
|  | // highlight-end | ||
|  | (async() => { | ||
|  |   const conn = new Airtable({ apiKey }); | ||
|  |   const table = conn.base(base).table("Sheet1"); | ||
|  |   const result = await table.select().all(); | ||
|  |   const aoo = result.map(r => r.fields); | ||
|  |   const ws = XLSX.utils.json_to_sheet(aoo); | ||
|  |   const wb = XLSX.utils.book_new(); | ||
|  |   XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); | ||
|  |   XLSX.writeFile(wb, "SheetJSAirtable.xlsb"); | ||
|  | })(); | ||
|  | ``` | ||
|  | 
 | ||
|  | 9) Replace the values in the highlighted lines with the PAT and workspace name. | ||
|  | 
 | ||
|  | 10) Run `node read.js`.  The script should write `SheetJSAirtable.xlsb`. The file | ||
|  | can be opened in Excel. | ||
|  | 
 | ||
|  | ### Importing Data
 | ||
|  | 
 | ||
|  | 11) Create a file `SheetJSAirpend.xlsx` with some new records in sheet `Sheet1`: | ||
|  | 
 | ||
|  |  | ||
|  | 
 | ||
|  | `npx xlsx-cli SheetJSAirpend.xlsx` should print the following data: | ||
|  | 
 | ||
|  | ```csv | ||
|  | Sheet1 | ||
|  | Name,Index | ||
|  | Someone Else,47 | ||
|  | ``` | ||
|  | 
 | ||
|  | 12) Save the following to `write.js`: | ||
|  | 
 | ||
|  | ```js title="write.js" | ||
|  | const Airtable = require("airtable"), XLSX = require("xlsx"); | ||
|  | // highlight-start | ||
|  | /* replace the value with the personal access token */ | ||
|  | const apiKey = "pat..."; | ||
|  | /* replace the value with the workspace name */ | ||
|  | const base = "app..."; | ||
|  | // highlight-end | ||
|  | (async() => { | ||
|  |   const conn = new Airtable({ apiKey }); | ||
|  |   const table = conn.base(base).table("Sheet1"); | ||
|  |   const wb = XLSX.readFile("SheetJSAirpend.xlsx"); | ||
|  |   const ws = wb.Sheets["Sheet1"]; | ||
|  |   const aoo = XLSX.utils.sheet_to_json(ws); | ||
|  |   await table.create(aoo.map(fields => ({ fields }))); | ||
|  | })(); | ||
|  | ``` | ||
|  | 
 | ||
|  | 13) Replace the values in the highlighted lines with the PAT and workspace name. | ||
|  | 
 | ||
|  | 14) Run `node write.js`.  Open Airtable and verify the new row: | ||
|  | 
 | ||
|  |  |