Giter Club home page Giter Club logo

airtable.js's People

Contributors

albreyb avatar benrazon avatar billyjanitsch avatar davidmally-at avatar dependabot[bot] avatar dougforster-at avatar evanhahn avatar fredzhao-at avatar jbbakst avatar jugglinmike avatar kasrak avatar kevinwilde-at avatar marks avatar minicat avatar msingleton avatar mzgoddard avatar nabeelfarooqui-at avatar newyorkpizza avatar paulmelnikow avatar rmeritz avatar runk avatar rwaldron avatar seankeenan-at avatar somehats avatar stewartmurrie avatar syrnick avatar thomaswang-at avatar tiagodws avatar unityoffairfax avatar yitianzhang-at avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

airtable.js's Issues

Related objects are fetched in reversed order

In the case of a many-to-many relationship, it is possible to drag-and-drop related items in order to change their order.
However, an API call gets the corresponding related objects in reversed order, compared to what is specified in Airtable. Is this normal behavior?

Difficult to import browser version in Meteor npm

Hello !

Just leaving the answers for others that may struggle with importing the browser version of airtable in constrained build environnement such as Meteor. It may also be useful to other build env, i believe. (or just for future me)

The browser based Airtable build is redefining require so it messes up with all your Meteor import npm stuff (that allows importing server based modules in the front with the exact same wording !). Thus, none of the tutorials work.

What worked for me was to first copy the airtable browser code in the /imports directory, in a file like airtable.browser.js (imports is a special directory from where you can load modules with import or require in meteor)

Then, find and replace all the occurences of require in the airtable browser code with requirez

Then, you can safely do what is documented to import airtable

const airtable = requirez('airtable');

export const base = new airtable({... ```

Best,
Mickael

maxRecords description in API docs is misleading

Hi,

I recently ran into an unexpected problem using the node.js lib, and sample code generated on the api docs for a table.

The following is from your documentation:

maxRecords (number)
optional

The maximum total number of records that will be returned.

However, this is misleading. It is not the total number of records returned, but the total records used for server-side pagination via cursor, e.g. if you spec 100 you can only ever get 100. To paginate properly you have to not specify this value.

This is not clearly explained anywhere. As someone trying to paginate a data set, it's implied to be the page size because "returned" is in the description.

To support promises

Hi There,

This is a feature request than issue. It will be nice to have promises supported instead of using callbacks. Thoughts are welcome.

Thanks.

Help with Authentication when proxying through CDN

Overview

I recently wrote an article on using Airtable (Airtable.js + lambda) as a content backend.
https://medium.com/@gtalarico/using-airtable-as-a-content-backend-e373cd0d9974

A few people mentioned the 5 req/sec rate limit could be an issue, so I am trying to add additional details about how one could add a CDN (eg. Cloudfront) to cache the requests and avoid the rate limit.

I created airtable as the origin on cloudfront, and set it up to pass through Authorization headers. I am able to successful use the CDN to proxy/cache the calls

Request works as expected through curl:

$ curl -L "https://d2j5hchu5g3uxq.cloudfront.net/v0/appNtnZ99fkL1cByn/entries?maxRecords=100&view=all" \
    -H "authorization: Bearer keyOmitted"

STATUS: 200

{"records":[{"id":"recW0FpRZMaQv5Ble","fields":{"title":"3D 
[... truncated ]

Requests fail when using airtable.js

I then make the exact same request When I make the same call through airtable.js, but I get AUTHENTICATION_REQUIRED.

I logged the options variable right before airtable.js runs runAction and the payload looks good and matches my curl, so I really can't understand why it would fail:

// run_action.js
# line 52
console.log(JSON.stringify(options))
request(options, function(error, resp, body) {
[ ... ]

Outputs:

// `options`
{
   "method":"GET",
   "url":"https://d2j5hchu5g3uxq.cloudfront.net/v0/appNtnZ99fkL1cByn/entries?maxRecords=100&view=all",
   "json":true,
   "timeout":300000,
   "headers":{
      "authorization":"Bearer keyOMITTED",
      "x-api-version":"0.1.0",
      "x-airtable-application-id":"appNtnZ99fkL1cByn",
      "User-Agent":"Airtable.js/0.1.0"
   },
   "agentOptions":{
      "rejectUnauthorized":false
   }
}

Response with status 500 in 686 ms.
Error during invocation:  s {
  error: 'AUTHENTICATION_REQUIRED',
  message: 'You should provide valid api key to perform this operation',
  statusCode: 401
}

I apologize as this may not be an issue with the lib but I am out of ideas here.
Let me know if you have any insights, otherwise feel free to close it.

Here is section I am adding to the article - I would be happy to add a wiki page or doc so other users can use the same approach to cache the rate limit:

Article Update:

image
image

Listing Bases and Tables

How can you programmatically list bases or tables? For example, what do I do if I don't know ahead of time what base to use and need to select it from a list of available bases?

Base has a property tables but it is undefined, which can be seen here.

var Airtable = require('airtable');
var base = new Airtable({apiKey: 'keyXXXXXXXXXX'}).base('appphXXXXXXXX');
console.log(base.tables);

>>undefined

But base('Base table') is working as expected.

Support creating Bases and updating Tables

The airtableBridge app is a github app for syncing data between github and airtable. The major difficulty for new accounts is that the users have to first create a new airtable base, with the same tables / columns. At the moment, we're getting around this by using the same airtable account and copying the original base. This won't scale :)

A secondary concern is doing automated table migrations... We will be updating our schema soon to support multiple repos and as a result, will want to roll out these changes to all the bases. This can't be done w/o api support

"Find" is returning any record by id, regardless of passed Table

It seems like I'm getting back any Record in a Base by Record id, regardless of the Table I pass.

That is, given Base A having Table "Users" and Table "Companies", with Table "Users" having a record with id "<ID 123>", the following snippets give the same response (returning User with record <ID 123>):

base('Users').find('<ID 123>')
base('Companies').find('<ID 123>')

Anyone else seeing this?

Updating a date field

I'd love for the ability to update a Date field, by just passing in a JS Date object.

Refuses to set unsafe User-Agent

Hello,

I'm attempting to use the Airtable library to send a newsletter signup email to the appropriate api route.

I'm using the example Airtable gives me as follows:

var Airtable = require('airtable');
var base = new Airtable({apiKey: 'MY_API_KEY'}).base('appgDopuvXbayMxX3');

base('Newsletter Signup').create({ email: '[email protected]' }, function(err, record) {
    if (err) { console.error(err); return; }
    console.log(record.getId());
});

However, I get the browser error 'Refused to set unsafe header "User-Agent"', about which I don't know what to do.

The response I get includes message: "Unknown field name: "email". This confuses me as well, as the form I'm trying to submit to has an email field.

Appreciate any help!

Securing Access Token

How could I secure the Access Token in a Website created for example with React or Angular completly client side?

I think, it would be a cool thing to have e.g. a PHP-Proxy-Class in addition to reroute the calls for specific app. but then the endpoints should be customizable in airtable.js

Rate limiting

I have a Node.js app which tries to upload more then 30 records a second. Airtable API doesn't allow us to do that. But this way the retry logic dies after ~3 mins for me.

I've solved it for myself with RateLimiter

Currently it looks something like this:

const RateLimiter = require('limiter').RateLimiter;
const limiter = new RateLimiter(5, 'second');

// ...

limiter.removeTokens(1, () => base('TAB').create({ ... }, err => err ? console.log(err) : void 0));

What if we implemented this in airtable.js?

Not sure how to set filterByFormula in API call

I can't figure out how filterByFormula values are supposed to be inputted.

My query for select().eachPage() looks like this:

{
  pageSize: 50,
  sort: [{field: 'Publish Date', direction: 'desc'}]
}

What I would like to do is filter by the field name of "Publish" to where only records that have "Publish" set as TRUE are returned.

I tried this but it didn't like it:

{
  pageSize: 50,
  filterByFormula: {Publish} = true,
  sort: [{field: 'Publish Date', direction: 'desc'}]
}

I based that syntax off the example in the documentation: NOT({Title} = '')

I read through the documentation here:
https://support.airtable.com/hc/en-us/articles/203255215-Formula-field-reference

But I still couldn't figure out how to format the values.

consider got

airtable.js would be very useful in serverless environments, which are very sensitive to package size. There are two different request libraries in the dependencies of this package, request and xhr. Please consider got as a smaller alternative (for node) and ky for browsers.

What functions are available?

It's not clear how this npm library can be used. What functions are available on an Airtable object? A code example or two would be great. The API documents how to write a URL to get responses from the API, but I'm assuming that making calls with JavaScript looks different. Maybe I'm wrong, but there's no examples to confirm or debunk that.

List queries with airtable backend and Rest API / How to do the load more query in the frontend?

Hello,

If I start from the api documentation to make a list requests to a table.
We figure out that the call is sequential, so there is no way to call page 4 before having fetched page 1, 2, 3...
and the fetchNextPage(); function allow to call next page in the backend.

base('projects').select({
    // Selecting the first 3 records in db:
    maxRecords: 3,
    view: "db"
}).eachPage(function page(records, fetchNextPage) {
    // This function (`page`) will get called for each page of records.

    records.forEach(function(record) {
        console.log('Retrieved', record.get('title'));
    });

    // To fetch the next page of records, call `fetchNextPage`.
    // If there are more records, `page` will get called again.
    // If there are no more records, `done` will get called.
    fetchNextPage();

}, function done(err) {
    if (err) { console.error(err); return; }
});

But how can we use that in the front end (using the node.js airtable.js in the backend).

I make a first query from the front.
The backend give me only the first 3 results.
Then which query should I make from the front so that the backend do no need to make again the query for the first 3 results so that I can get next results ?

If I do all from the frontend, I can assign the fetchNextPage(); to the load more button.

But if I want to use a node.js api ?

Not possible @kasrak

Unfriendly docs

Hi, I'm using airtable and loving every bit of it.
I'm very new to web development so I don't understand how to use this package to make my calls instead of request, the package I've been using so far to connect to Airtable. I'm using node, express and airtable to build a catalogue of things on a website.

I'd appreciate richer instructions on the methods and things I can do by installing this module.
I apologise if this is too basic.

How to know when on last page of query

So I've written a wrapper for this library that I've been using for more than a year but need to add a method for fetching all records together

Heres what I have

let getAllDataFromTable = (table) => (filterQuery = {}) => {
  return new Promise((resolve, reject) => {
    let data = [];
    table.select(filterQuery)
     
    .eachPage((records, fetchNextPage) => {
      data = data.concat(records);
      fetchNextPage();
    });
  });
}

I'm not sure when to call resolve(data) because there's no way for me to know when on the last page. How come fetchNextPage() doesn't return anything or have a 3rd parameter to know when on the last page?

The documentation shows that page will be called or done will be called, is there any way to know what's about to be called?

image

Add license

Since you're providing this client and linking to it in the Airtable API documentation, I think we all presume you would like us to use it in our software! ๐Ÿ˜Š But it would be useful (legally, and to encourage everyone to use the software) to provide an explicit LICENSE.txt so we know our rights.

I see that https://github.com/Airtable/airtable-ruby is licensed under the MIT License. Perhaps that would be appropriate here as well?

Thanks so much for your work and for providing this great tool!

CORS

Is CORS enabled for air table? I would like to use the airtable client on the browser side.

New Batch Abilities

I see latest release has the batch functions available. Are they still not ready for production? or does this release mean they can be used in production?

Also, will they only work on accounts that have that beta turned on? or has it been rolled out to all accounts?

And documentation here says typecast works. My understanding was that typecast didn't yet work for batch. Has that been added?

Finally, is batch limit still 100 or has that been increased? If still 100, will it be increased when ready for production? (please :) )

Thanks for getting this out there. Excited to start using!

eachPage Promisified behaviour

@kasrak Thanks for this work.
Could you also provide a snippet showing how the eachPage of a Query object behaves when promisifed?

Since the promise versions are used when the last callback is omitted, for the eachPage version that would be the done method. (Although the callbackArgIndex is specified, it still points at the last argument which is the done callback).

Is this the correct promisified usage of the eachPage function?

const data = [];
await table.select({}).eachPage((records, next) => {
  data.push(...records);
  next();
});

If so, it is still a bit weird to have to use a callback and implement the iterator/accumulator. where the promise happinness cannot be used to handle the async io taking place.

perhaps a better API would return a cursor with a promisified "next" method on it.. (waving hands here)

const cursor = await table.select({}).eachPage();
while (cursor.hasMore) {
  const moreRecords = await cursor.next();
  ...
}

Thanks Again!

How do I use "err" without JSON.stringify()?

Hello,

I'm a relative novice when it comes to JavaScript so forgive me if this question is very basic.

I'm trying to return the value err to the client but the string "Class " is being prepended to the output unless I do JSON.stringify(err).

Here's what I see in my console:

image

But here's what I see when I use JSON.stringify(err):

"{\"error\":\"INVALID_FILTER_BY_FORMULA\",\"message\":\"The formula for filtering records is invalid: please check your formula text.\",\"statusCode\":422}"

In this case, "Class " is nowhere to be found and I can return the response to the client without an issue. Where is "Class " coming from and how do I use err without JSON.stringify() first?

Rate limiting for eachPage

According to the API docs, there is a limit of 5 RPS. Would be great to conform to it out of the box.

save() coughs on formulas

Hi, if I use the save() method on a table that happens to have formulas, i get errors.

eg consider:

const records = await base("MyTable").select({view: "Grid view"}).all();
const someRecord = records[0];
record.fields.description = "hello";
record.save();

This code works in general, but if the table happens to have a formula field, then it doesn't because save attempts to overwrite the formula field by a concrete value.

My workaround is to do this:

const records = await base("MyTable").select({view: "Grid view"}).all();
const someRecord = records[0];
record.fields.description = "hello";
delete record.fields.someFormulaField;
record.save();

But it's messy and, notably, not forward compatible. I found save by accident but I think it makes your API very ergonomic! So my compliments :-)

Airtable.browser.js: Uncaught ReferenceError: require is not defined

Problem:

While attempting to use Airtable.browser.jsusing the test in the readme I received.

Uncaught ReferenceError: require is not defined

Expected:

No Errors.

Steps to Reproduce:

From project root.

npm install airtable
cd ./node_modules/airtable/test/test_files
python -m SimpleHTTPServer

Navigate to test page and view console.

dyld: lazy symbol binding failed: Symbol not found: _SSL_CTX_set_alpn_protos

When running the curl

"https://api.airtable.com/v0/..." -H "Authorization: Bearer ...,

there is an error:

dyld: lazy symbol binding failed: Symbol not found: _SSL_CTX_set_alpn_protos
  Referenced from: /Users/.../anaconda/bin/../lib/libcurl.4.dylib
  Expected in: /Users/.../anaconda/bin/../lib/libssl.1.0.0.dylib

dyld: Symbol not found: _SSL_CTX_set_alpn_protos
  Referenced from: /Users/.../anaconda/bin/../lib/libcurl.4.dylib
  Expected in: /Users/.../anaconda/bin/../lib/libssl.1.0.0.dylib

How do you solve this?

Use with Angular JS

Hi
Could you give an example on how to use it with promise in Angular JS.
This is my example code:
baseAirport('Airport Shuttle Requests').select({
maxRecords: 10,
view: 'All Departures and Arrivals',
filterByFormula: "Email='" + $scope.form_email + "'"
}).eachPage(function page(records, fetchNextPage) {
records.forEach(function(record) {
console.log('Retrieved ', record.get('Name'));
$scope.result.append(record.get('Name'));
});
fetchNextPage();
}, function done(error) {
console.log(error);
});
The data comes through but I don't how to connect it with a promise in angularJS so that the $scope.result gets refreshed in the DOM automatically

Field Types

Hi, is there a way to access the field types of each column? I need all except those with formulas. I am currently using Node.js

Add or document fetching linked records?

Hi! This is either a feature request or documentation improvement request, depending :-)

It's unclear how one is supposed to efficiently retrieve linked records. e.g. a table called Blogs with linked Posts. A Blogs record might look like this:

{
  "Name": "My Blog",
  "Posts" [
     "rec123",
     "rec456"
  ]
}

How does one fetch those linked Posts records, without fetching them one at a time using find? ~20 minutes of googling, looking through https://airtable.com/api, and various forums hasn't turned up anything, though it seems like this would be a very common operation.

I hoped for something along these lines:

// Supported by select as record ids
base("Posts").select({records: ["rec123", "rec456"]})

// Supported by select as expansion/hydration
base("Blogs").select({expand: ["Posts"]}).all().then(blogs => {
  blogs.forEach(blog => {
    blog.get("Posts").forEach(...)
  })
})

// On a Blogs record directly
base("Blogs").select().all().then(posts => {
  posts.forEach(post => {
    post.fetchLinks("Posts").then(...) // fetchLinks isn't a great name, but you get the idea
  })
})

// Supported by find
base("Posts").find(["rec123", "rec456"]).then(posts => { ... })

// My least favorite, but through filterByFormula if it supported some sort of IN operation, which I don't think it does
base("Posts").select({filterByFormula: "IN(["rec123", "rec456"], RECORD_ID())"})

If fetching multiple records by their ids is supported today, how is it done, and can it be documented somewhere clearly? If it's not possible, I'd like to request it be added.

Thanks!

how do i use 'forEach' ?

the 100 records limit per request is a pain to deal with

i see the 'list' method takes a options as in {view: XX}
where as forEach doesnt.
but forEach calls list

forEach also seems to pass the document (not an error) as the first param.

can you give me a short example of forEach to get the data for a full sheet > 100 lines?

i'm using as below and getting data back in the error param
also your module seems to be spitting out logs

import AppConfig = require("../config/AppConfig");

var baseKey = 'XXXXXX';
var sheetName = 'testdata'

var Airtable = require('airtable');
var base = new Airtable({ apiKey: AppConfig.AIRTABLE_KEY }).base(baseKey);

function done(err, doc) {
    console.log("done");
    console.log("err", err);
    console.log("doc", doc);
}

function saveRecords(err, records, newOffset) {
    if (err) { console.log("ERR:", err); return; }
    console.log("records", records);

    var data = [];
    records.forEach(function(record) {
        data.push(record.fields)
        // console.log('Retrieved ', record.fields);
    });
    console.log(">DATA: -----------")
    console.log(JSON.stringify(data, null, 4));
    console.log("<enddata: -----------")
};

// https://github.com/Airtable/airtable.js/blob/master/lib/table.js#L23
// _forEachRecord: function(callback, done) {
base(sheetName).forEach(saveRecords, done)


// https://github.com/Airtable/airtable.js/blob/master/lib/table.js#L61
// _listRecords: function(limit, offset, opts, done) {
base(sheetName).list(null, null, {view: 'main'}, saveRecords, done);

How to access Lookup columns

If my record has a Lookup column, I struggle to get the related value using the client.

Example:

record.get('lookupColumnName') // is undefined

Version 0.5.1

unable to find how to deal with [] in the filterByFormula

I have been reading your api doc since an hour and tried multiple thing in postman.
I cannot find all query that imply array
like
https://api.airtable.com/v0/appD26Y6hJLSadC6d/projects?fields=["title","buildYear"]
Where I want to have the list with only the 2 listed fields
fields=["title","buildYear"]

And a query on a relation field
https://api.airtable.com/v0/appD26Y6hJLSadC6d/projects?architect=["recpxHgMoiA5Dh9i7"]
Where recpxHgMoiA5Dh9i7 is the id of an architect in another table that projects but related thanks to the architect column.

The doc of airtable.js is very limited, you should improve it if you want to have more usage of which api that seems well built.

I've written my personal doc in a more partical format to quickly get success with my queries :)
https://github.com/sinsunsan/archiref_wiki/wiki/airtable

Support primary key values

Currently, updating records, fetching records, and updating linked fields require the airtable record id.

e.g. If there is a Users table with a primary key column name, and I want to update the user record "John", I have to first, select the record with a formula {name}=${name} and use the records ID.

This process is pretty cumbersome. see example

It would be better if I could transparently fetch/update w/ the primary key values

airtable("Users").update("John", ...)

Response contains my API key

Right now when I do:

base('mybase').select({
    // Selecting the first 3 records in Grid view:
    maxRecords: 3,
    view: "Grid view"
}).eachPage(function page(records, fetchNextPage) {
    // This function (`page`) will get called for each page of records.

    records.forEach(function(record) {
        console.log('Retrieved', record.get('Ingredient'));
    });

    // To fetch the next page of records, call `fetchNextPage`.
    // If there are more records, `page` will get called again.
    // If there are no more records, `done` will get called.
    fetchNextPage();

}, function done(err) {
    if (err) { console.error(err); return; }
});

The response (that's console logged here) contains something that looks like this:

{
      "_table": {
        "_base": {
          "_airtable": {
            "_apiKey": "myrealapikey",
            "_endpointUrl": "https://api.airtable.com",
            "_apiVersion": "0.1.0",
            "_apiVersionMajor": "0",
            "_allowUnauthorizedSsl": false,
            "_noRetryIfRateLimited": false,
            "requestTimeout": 300000
          },
          "_id": "something"
        },
        "id": null,
        "name": "something"
      },

This causes some issues when I'm working on for example doing live coding or demo projects (I work in developer education). This happened to a colleague of mine and he had to reset his key.

In-browser demo is broken

I'm attempting to see how the in-browser functionality is, but when I do exactly what is written in the README, all I get are errors saying require is not defined. When I add require.js to my html file, I'm getting the following error: Module name "airtable" has not been loaded yet for context: _. Use require([]).

Is there a step missing from the README?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.