feat: add read-only support of the meta API (#13)

* Add bases API.

* Implement get tables schema

* Rename GetBase to GetBaseSchema

* Add tests

* Update doc
This commit is contained in:
François de Metz
2023-01-01 15:18:29 +01:00
committed by GitHub
parent 6275e61012
commit 1b1e6e9e92
7 changed files with 275 additions and 0 deletions

View File

@@ -43,6 +43,18 @@ You should get `your_api_token` in the airtable [account page](https://airtable.
client := airtable.NewClient("your_api_token")
```
### List bases
```Go
bases, err := client.GetBases().WithOffset("").Do()
```
### Get base schema
```Go
schema, err := client.GetBaseSchema("your_database_ID").Do()
```
### Get table
To get the `your_database_ID` you should go to [main API page](https://airtable.com/api) and select the database.

89
base.go Normal file
View File

@@ -0,0 +1,89 @@
package airtable
import (
"net/url"
)
// Base type of airtable base.
type Base struct {
ID string `json:"id"`
Name string `json:"name"`
PermissionLevel string `json:"permissionLevel"`
}
// Base type of airtable bases.
type Bases struct {
Bases []*Base `json:"bases"`
Offset string `json:"offset,omitempty"`
}
type Field struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Description string `json:"description"`
}
type View struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
}
type TableSchema struct {
ID string `json:"id"`
PrimaryFieldID string `json:"primaryFieldId"`
Name string `json:"name"`
Description string `json:"description"`
Fields []*Field `json:"fields"`
Views []*View `json:"views"`
}
type Tables struct {
Tables []*TableSchema `json:"tables"`
}
// GetBasesWithParams get bases with url values params
// https://airtable.com/developers/web/api/list-bases
func (at *Client) GetBasesWithParams(params url.Values) (*Bases, error) {
bases := new(Bases)
err := at.get("meta", "bases", "", params, bases)
if err != nil {
return nil, err
}
return bases, nil
}
// Table represents table object.
type BaseConfig struct {
client *Client
dbId string
params url.Values
}
// GetBase return Base object.
func (c *Client) GetBaseSchema(dbId string) *BaseConfig {
return &BaseConfig{
client: c,
dbId: dbId,
}
}
// Do send the prepared
func (b *BaseConfig) Do() (*Tables, error) {
return b.GetTablesWithParams()
}
// GetTablesWithParams get tables from a base with url values params
// https://airtable.com/developers/web/api/get-base-schema
func (b *BaseConfig) GetTablesWithParams() (*Tables, error) {
tables := new(Tables)
err := b.client.get("meta/bases", b.dbId, "tables", nil, tables)
if err != nil {
return nil, err
}
return tables, nil
}

25
base_test.go Normal file
View File

@@ -0,0 +1,25 @@
package airtable
import (
"testing"
)
func TestGetBaseSchema(t *testing.T) {
client := testClient(t)
baseschema := client.GetBaseSchema("test")
baseschema.client.baseURL = mockResponse("base_schema.json").URL
result, err := baseschema.Do()
if err != nil {
t.Errorf("there should not be an err, but was: %v", err)
}
if len(result.Tables) != 2 {
t.Errorf("there should be 2 tales, but was %v", len(result.Tables))
}
baseschema.client.baseURL = mockErrorResponse(400).URL
_, err = baseschema.Do()
if err == nil {
t.Errorf("there should be an err, but was nil")
}
}

37
get-bases.go Normal file
View File

@@ -0,0 +1,37 @@
package airtable
import (
"net/url"
)
// GetBasesConfig helper type to use in.
// step by step get bases.
type GetBasesConfig struct {
client *Client
params url.Values
}
// GetBases prepare step to get bases.
func (c *Client) GetBases() *GetBasesConfig {
return &GetBasesConfig{
client: c,
params: url.Values{},
}
}
// Pagination
// The server returns one page of bases at a time.
// If there are more records, the response will contain an offset.
// To fetch the next page of records, include offset in the next request's parameters.
// WithOffset Pagination will stop when you've reached the end of your bases.
func (gbc *GetBasesConfig) WithOffset(offset string) *GetBasesConfig {
gbc.params.Set("offset", offset)
return gbc
}
// Do send the prepared get records request.
func (gbc *GetBasesConfig) Do() (*Bases, error) {
return gbc.client.GetBasesWithParams(gbc.params)
}

25
get-bases_test.go Normal file
View File

@@ -0,0 +1,25 @@
package airtable
import (
"testing"
)
func TestGetBases_Do(t *testing.T) {
client := testClient(t)
bases := client.GetBases()
bases.client.baseURL = mockResponse("get_bases.json").URL
result, err := bases.WithOffset("0").Do()
if err != nil {
t.Errorf("there should not be an err, but was: %v", err)
}
if len(result.Bases) != 2 {
t.Errorf("there should be 2 bases, but was %v", len(result.Bases))
}
bases.client.baseURL = mockErrorResponse(400).URL
_, err = bases.Do()
if err == nil {
t.Errorf("there should be an err, but was nil")
}
}

72
testdata/base_schema.json vendored Normal file
View File

@@ -0,0 +1,72 @@
{
"tables": [
{
"description": "Apartments to track.",
"fields": [
{
"description": "Name of the apartment",
"id": "fld1VnoyuotSTyxW1",
"name": "Name",
"type": "singleLineText"
},
{
"id": "fldoaIqdn5szURHpw",
"name": "Pictures",
"type": "multipleAttachments"
},
{
"id": "fldumZe00w09RYTW6",
"name": "District",
"options": {
"inverseLinkFieldId": "fldWnCJlo2z6ttT8Y",
"isReversed": false,
"linkedTableId": "tblK6MZHez0ZvBChZ",
"prefersSingleRecordLink": true
},
"type": "multipleRecordLinks"
}
],
"id": "tbltp8DGLhqbUmjK1",
"name": "Apartments",
"primaryFieldId": "fld1VnoyuotSTyxW1",
"views": [
{
"id": "viwQpsuEDqHFqegkp",
"name": "Grid view",
"type": "grid"
}
]
},
{
"fields": [
{
"id": "fldEVzvQOoULO38yl",
"name": "Name",
"type": "singleLineText"
},
{
"description": "Apartments that belong to this district",
"id": "fldWnCJlo2z6ttT8Y",
"name": "Apartments",
"options": {
"inverseLinkFieldId": "fldumZe00w09RYTW6",
"isReversed": false,
"linkedTableId": "tbltp8DGLhqbUmjK1",
"prefersSingleRecordLink": false
},
"type": "multipleRecordLinks"
}
],
"id": "tblK6MZHez0ZvBChZ",
"name": "Districts",
"primaryFieldId": "fldEVzvQOoULO38yl",
"views": [
{
"id": "viwi3KXvrKug2mIBS",
"name": "Grid view",
"type": "grid"
}
]
}
]
}

15
testdata/get_bases.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"bases": [
{
"id": "appLkNDICXNqxSDhG",
"name": "Apartment Hunting",
"permissionLevel": "create"
},
{
"id": "appSW9R5uCNmRmfl6",
"name": "Project Tracker",
"permissionLevel": "edit"
}
],
"offset": "itr23sEjsdfEr3282/appSW9R5uCNmRmfl6"
}