Skip to content

Commit 28e9a23

Browse files
committed
Remove assertions that would panic and instead return errors including from airtable.New() to give greater control to the library's user on how to handle errors
1 parent 004213e commit 28e9a23

File tree

6 files changed

+60
-34
lines changed

6 files changed

+60
-34
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ import (
3131
airtableAPIKey := os.Getenv("AIRTABLE_API_KEY")
3232
baseID := "apphllLCpWnySSF7q" // replace this with your airtable base's id
3333

34-
client := airtable.New(airtableAPIKey, baseID)
34+
client, err := airtable.New(airtableAPIKey, baseID)
35+
if err != nil {
36+
panic(err)
37+
}
3538
```
3639
You can now call methods on the client instance. All client methods are documented in the project's <a href="https://godoc.org/github.com/fabioberger/airtable-go">GoDoc page</a>. You can also check out the <a href="https://github.com/fabioberger/airtable-go/blob/master/tests/stubbed_tests/client_test.go">stubbed</a> and <a href="https://github.com/fabioberger/airtable-go/blob/master/tests/integration_tests/client_test.go">integration</a> tests included in this project for working examples of all the client methods and options.
3740

client.go

+18-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package airtable
33
import (
44
"bytes"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"io/ioutil"
89
"net/http"
@@ -29,17 +30,21 @@ type Client struct {
2930
}
3031

3132
// New creates a new instance of the Airtable client.
32-
func New(apiKey, baseID string) *Client {
33-
utils.AssertIsAPIKey(apiKey)
34-
utils.AssertIsBaseID(baseID)
33+
func New(apiKey, baseID string) (*Client, error) {
34+
if !utils.IsValidAPIKey(apiKey) {
35+
return nil, errors.New("invalid API Key encountered")
36+
}
37+
if !utils.IsValidBaseID(baseID) {
38+
return nil, errors.New("invalid base ID encountered")
39+
}
3540

3641
c := Client{
3742
apiKey: apiKey,
3843
baseID: baseID,
3944
ShouldRetryIfRateLimited: true,
4045
HTTPClient: http.DefaultClient,
4146
}
42-
return &c
47+
return &c, nil
4348
}
4449

4550
type recordList struct {
@@ -106,7 +111,9 @@ func (c *Client) recursivelyListRecordsAtOffset(endpoint string, offsetHash stri
106111

107112
// RetrieveRecord returns a single record from a given Airtable table.
108113
func (c *Client) RetrieveRecord(tableName string, recordID string, recordHolder interface{}) error {
109-
utils.AssertIsRecordID(recordID)
114+
if err := utils.CheckForValidRecordID(recordID); err != nil {
115+
return err
116+
}
110117

111118
endpoint := fmt.Sprintf("%s/%s/%s/%s", apiBaseURL, c.baseID, tableName, recordID)
112119
rawBody, err := c.request("GET", endpoint, nil)
@@ -141,7 +148,9 @@ type updateBody struct {
141148
// UpdateRecord updates an existing record in an Airtable table and updates the new field values in
142149
// the `record` struct passed in.
143150
func (c *Client) UpdateRecord(tableName, recordID string, updatedFields map[string]interface{}, record interface{}) error {
144-
utils.AssertIsRecordID(recordID)
151+
if err := utils.CheckForValidRecordID(recordID); err != nil {
152+
return err
153+
}
145154

146155
endpoint := fmt.Sprintf("%s/%s/%s/%s", apiBaseURL, c.baseID, tableName, recordID)
147156
body := updateBody{}
@@ -158,7 +167,9 @@ func (c *Client) UpdateRecord(tableName, recordID string, updatedFields map[stri
158167

159168
// DestroyRecord deletes a record from an Airtable table by recordID
160169
func (c *Client) DestroyRecord(tableName, recordID string) error {
161-
utils.AssertIsRecordID(recordID)
170+
if err := utils.CheckForValidRecordID(recordID); err != nil {
171+
return err
172+
}
162173

163174
endpoint := fmt.Sprintf("%s/%s/%s/%s", apiBaseURL, c.baseID, tableName, recordID)
164175
if _, err := c.request("DELETE", endpoint, nil); err != nil {

example_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ func ExampleNew() {
1111
airtableAPIKey := os.Getenv("AIRTABLE_API_KEY")
1212
baseID := "apphllLCpWnySSF7q"
1313

14-
client := airtable.New(airtableAPIKey, baseID)
14+
client, _ := airtable.New(airtableAPIKey, baseID)
1515

1616
fmt.Println(client)
1717
}
1818

1919
func ExampleClient_CreateRecord() {
20-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
20+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
2121

2222
type task struct {
2323
AirtableID string
@@ -37,15 +37,15 @@ func ExampleClient_CreateRecord() {
3737
}
3838

3939
func ExampleClient_DestroyRecord() {
40-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
40+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
4141

4242
if err := client.DestroyRecord("TABLE_NAME", "RECORD_ID"); err != nil {
4343
panic(err)
4444
}
4545
}
4646

4747
func ExampleClient_ListRecords() {
48-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
48+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
4949

5050
type task struct {
5151
AirtableID string
@@ -64,7 +64,7 @@ func ExampleClient_ListRecords() {
6464
}
6565

6666
func ExampleClient_RetrieveRecord() {
67-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
67+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
6868

6969
type task struct {
7070
AirtableID string
@@ -83,7 +83,7 @@ func ExampleClient_RetrieveRecord() {
8383
}
8484

8585
func ExampleClient_UpdateRecord() {
86-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
86+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
8787

8888
type task struct {
8989
AirtableID string
@@ -108,7 +108,7 @@ func ExampleClient_UpdateRecord() {
108108
}
109109

110110
func ExampleListParameters() {
111-
client := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
111+
client, _ := airtable.New("AIRTABLE_API_KEY", "BASE_ID")
112112

113113
type task struct {
114114
AirtableID string

tests/integration_tests/client_test.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ type ClientSuite struct{}
1515

1616
var _ = Suite(&ClientSuite{})
1717

18-
var client = airtable.New(testConfigs.AirtableTestAPIKey, testConfigs.AirtableTestBaseID)
18+
var client *airtable.Client
19+
20+
func (s *ClientSuite) SetUpSuite(c *C) {
21+
var err error
22+
client, err = airtable.New(testConfigs.AirtableTestAPIKey, testConfigs.AirtableTestBaseID)
23+
if err != nil {
24+
c.Error(err)
25+
}
26+
}
1927

2028
func (s *ClientSuite) TestListTeammateRecords(c *C) {
2129
teamMates := []testBase.TeamMate{}

tests/stubbed_tests/client_test.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"testing"
88
"time"
99

10-
"github.com/fabioberger/airtable-go"
10+
airtable "github.com/fabioberger/airtable-go"
1111
"github.com/fabioberger/airtable-go/tests/test_base"
1212
"github.com/fabioberger/airtable-go/tests/test_configs"
1313
. "gopkg.in/check.v1"
@@ -39,7 +39,15 @@ func (f fileRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
3939
return httpResponse, nil
4040
}
4141

42-
var client = airtable.New(testConfigs.AirtableTestAPIKey, testConfigs.AirtableTestBaseID)
42+
var client *airtable.Client
43+
44+
func (s *ClientSuite) SetUpSuite(c *C) {
45+
var err error
46+
client, err = airtable.New(testConfigs.AirtableTestAPIKey, testConfigs.AirtableTestBaseID)
47+
if err != nil {
48+
c.Error(err)
49+
}
50+
}
4351

4452
var fakeRecordID = "recSG8Ytl8KWpFAKE"
4553

utils/utils.go

+12-16
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,22 @@ func SwitchCaseError(name string, value interface{}) error {
1111
return fmt.Errorf("Unrecognized %s: %v", name, value)
1212
}
1313

14-
// Assert panics with message if the condition is false.
15-
func Assert(condition bool, message string) {
16-
if !condition {
17-
panic(message)
18-
}
19-
}
20-
21-
// AssertIsAPIKey asserts that is was supplied a correctly formatted API key
22-
func AssertIsAPIKey(apiKey string) {
23-
Assert(isValidAirtableID(apiKey, "key"), "invalid API Key encountered")
14+
// IsValidAPIKey checks for a correctly formatted API key
15+
func IsValidAPIKey(apiKey string) bool {
16+
return isValidAirtableID(apiKey, "key")
2417
}
2518

26-
// AssertIsBaseID asserts that is was supplied a correctly formatted base ID
27-
func AssertIsBaseID(baseID string) {
28-
Assert(isValidAirtableID(baseID, "app"), "invalid base ID encountered")
19+
// IsValidBaseID checks for a correctly formatted base ID
20+
func IsValidBaseID(baseID string) bool {
21+
return isValidAirtableID(baseID, "app")
2922
}
3023

31-
// AssertIsRecordID asserts that is was supplied a correctly formatted record ID
32-
func AssertIsRecordID(recordID string) {
33-
Assert(isValidAirtableID(recordID, "rec"), "invalid record ID encountered")
24+
// CheckForValidRecordID checks if a correctly formatted record ID was supplied, returns error if not
25+
func CheckForValidRecordID(recordID string) error {
26+
if !isValidAirtableID(recordID, "rec") {
27+
return fmt.Errorf("Invalid recordID encountered: %s", recordID)
28+
}
29+
return nil
3430
}
3531

3632
func isValidAirtableID(id, expectedPrefix string) bool {

0 commit comments

Comments
 (0)