Skip to content

Squirrel-Entreprise/airtable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Golang Airtable API v2.0

GoDoc Go Go Report Card codecov

A modern Go package to access the Airtable API with enhanced features including context support, intelligent retry logic, and improved error handling.

What's New in v2.0

  • Context Support: All methods now support context.Context for cancellation and timeouts
  • Intelligent Retry Logic: Exponential backoff retry with configurable options
  • Enhanced Error Handling: Custom error types with detailed error information
  • Configurable HTTP Client: Customizable timeout, retry settings, and HTTP client
  • Input Validation: Comprehensive parameter validation
  • Updated Go Version: Requires Go 1.21+
  • Improved Documentation: All comments and documentation in English

Table of contents

Installation

    go get github.com/Squirrel-Entreprise/airtable

Aitable API

Airtable uses simple token-based authentication. To generate or manage your API key, visit your account page.

Getting started

Basic Usage

Initialize client with default options

a := airtable.New("your-api-key", "your-base-id", false)

Advanced Configuration

Create client with custom options

options := airtable.ClientOptions{
    Timeout:       30 * time.Second,
    MaxRetries:    3,
    RetryDelay:    time.Second,
    MaxRetryDelay: 30 * time.Second,
    UserAgent:     "my-app/1.0",
    Debug:         true,
}
a := airtable.NewWithOptions("your-api-key", "your-base-id", options)

Context Support

All methods support context for cancellation and timeouts

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

var result airtable.AirtableList
err := a.ListWithContext(ctx, params, &result)

List table records

productsParameters := airtable.Parameters{
	Name:       "Products", // Name of the table
	MaxRecords: "100", // Max records to return
    	PageSize:   "10",
	View:       "Grid view", // View name
	FilterByFormula: fmt.Sprintf(`Name="%s"`, "Apple"), // Filter by formula
	Fields: []string{ // Fields to return
		"Name",
		"Category",
	},
	Sort: []airtable.Sort{
		{
			Field:     "Category",
			Direction: airtable.Descending,
		},
	},
}

var products airtable.AirtableList

if err := a.List(productsParameters, &products); err != nil {
	fmt.Println(err)
}

for _, p := range products.Records {
	fmt.Println(p.ID, p.Fields["Name"], p.Fields["Category"])
}

Pagination, and ListPager

If you make a request that needs to return more records than fits in a page (determined by Parameters.PageSize), the response AirtableList's Offset field will be non-empty.

For the small 5-record table below:

| Name  |
| ----- |
| R-001 |
| R-002 |
| R-003 |
| R-004 |
| R-005 |

Getting a list with a page-size of 2:

var (
	params = airtable.Parameters{
		Name:     "Products",
		PageSize: "2",
		Fields:   []string{"Name"},
	}
	resList airtable.AirtableList
)

a.List(params, &resList)

resList will have its Offset field set, in addition to its Records field:

fmt.Println("offset:", resList.Offset)
for _, p := range resList.Records {
	fmt.Println("  name:", p.Fields["Name"])
}

// offset: itrUBoYIqbyPWClt7/rec15x8Y8iIFy0zLD
//   name: R-001
//   name: R-002

To get the next two products (R-003, R-004), add that offset into params before making the List call again:

params.Offset = resList.Offset
resList.Offset = ""
a.List(params, &resList)

Printing resList like before:

// offset: itr9dgLqRfeSslQ2G/rec1YiWuByyHHe2cM
//   name: R-003
//   name: R-004

Repeat to get the last product:

params.Offset = resList.Offset
resList.Offset = ""
a.List(params, &resList)

// offset:
//   name: R-005

Note that offset is blank in the printout. When the Airtable API has sent all the records it can, there will be no more pages, it omits the "offset" key in the JSON. We need to be careful to always clear/reset resList.Offset to an empty string before making the call to List. If we don't manually clear resList.Offset, it will keep the old offset and we won't get the signal from the API that there will be no more pages.

To make getting all records regardless of record count and page size, this client provides a ListPager. Call your pagers Next method to get records back, at most page-size records at a time. When all pages have been listed (no more records), Next returns an ErrEOL ("end of list").

Fetching the same five products two-at-a-time, like above, now looks like:

pgr := NewListPager(a, params)
for {
	products, err := pgr.Next()
	if err != nil {
		if err == ErrEOL {
			break
		}
		log.Fatal(err)
	}

	fmt.Println("offset:", pgr.Offset())
	for _, p := range products {
		fmt.Println("  name:", p.Name)
	}
}

ListPager manages the offset logic, making sure you get all the records you expect with no fuss.

Get table record

product := airtable.AirtableItem{}
table := airtable.Parameters{Name: "Products"}
if err := a.Get(table, "recj2fwn8nSQhR9Gg", &product); err != nil {
	fmt.Println(err)
}

fmt.Println(product.ID, product.Fields["Name"], product.Fields["Category"])

Create table record

type porductPayload struct {
	Fields struct {
		Name     string  `json:"Name"`
		Category string  `json:"Category"`
		Price    float64 `json:"Price"`
	} `json:"fields"`
}

newProduct := porductPayload{}
newProduct.Fields.Name = "Framboise"
newProduct.Fields.Category = "Fruit"
newProduct.Fields.Price = 10.0

payload, err := json.Marshal(newProduct)
if err != nil {
	fmt.Println(err)
}

product := airtable.AirtableItem{}

table := airtable.Parameters{Name: "Products"}
if err := a.Create(table, payload, &product); err != nil {
	fmt.Println(err)
}

fmt.Println(product.ID, product.Fields["Name"], product.Fields["Price"])

Update table record

type porductPayload struct {
	Fields struct {
		Price float64 `json:"Price"`
	} `json:"fields"`
}

updateProduct := porductPayload{}
updateProduct.Fields.Price = 11.0

payload, err := json.Marshal(updateProduct)
if err != nil {
	fmt.Println(err)
}

product := airtable.AirtableItem{}

table := airtable.Parameters{Name: "Products"}
if err := a.Update(table, "recgnmCzr7u3jCB5w", payload, &product); err != nil {
	fmt.Println(err)
}

fmt.Println(product.ID, product.Fields["Name"], product.Fields["Price"])

Delete table record

table := airtable.Parameters{Name: "Products"}
if err := a.Delete(table, "recgnmCzr7u3jCB5w"); err != nil {
	fmt.Println(err)
}

About

API wrapper for Airtable

Topics

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •  

Languages