Discussions

 View Only

How To Make Bulk Use Of API?

  • 1.  How To Make Bulk Use Of API?

    Posted 11-25-2018 19:26
    How To Make Bulk Use Of API?

    This may come as a surprise to native builders but in the near future everyone will be using the API to manipulate their QuickBase applications and eventually the whole point and click graphical user interface will go away. Yes its true - there will be nothing but API and JavaScript. What a glorious day that will be! To prepare you for this day I thought I would demonstrate how to make bulk use of the API using modern JavaScript. When I say modern JavaScript this will not be an exaggeration as we are going to use the most recent JavaScript features including asynchronous iterators and a whole bunch of ES6 sugar.

    Let's take as a demo the creation of a large number of new fields using the action API_AddField. You might think you could just wrap a simple for loop around API_AddField and be done with the task in a jiffy. Unfortunately, if you tried this your browser would slow to a crawl as the for loop would unleash a flood of network calls as fast as the for loop executed. To successfully perform this type of bulk use of the API you have to use some special features in modern JavaScipt to orchestrate and sequence the multiple API calls so as to avoid flooding the network with simultaneous AJAX requests.

    Assume we want to add one of each field type to a table and the field's label and type are identified by an object similar to this:
      const fields = [
        {label: "Checkbox", type: "checkbox"},
        {label: "Date", type: "date"},
        {label: "Duration", type: "duration"},
        {label: "Email Address", type: "email"},
        {label: "File Attachment", type: "file"},
        {label: "List - User", type: "multiuserid"},
        {label: "Multi-select Text", type: "multitext"},
        {label: "Numeric", type: "float"},
        {label: "Numeric - Currency", type: "currency"},
        {label: "Numeric - Percent", type: "percent"},
        {label: "Numeric - Rating", type: "rating"},
        {label: "Phone Number", type: "phone"},
        {label: "Report Link", type: "dblink"},
        {label: "Text", type: "text"},
        {label: "Time Of Day", type: "timeofday"},
        {label: "URL", type: "url"},
        {label: "User", type: "userid"}
      ];
    And of course we want some type of for loop that will take a dbid and our fields object above and on each iteration of the for loop will create the new field and give us access to the label, type and fid of each newly created field:
      for <dbidRecords, fields> {
        console.log('${label}, ${type}, ${fid}');
      }
    First, we will need something called an async function named addField(dbid, label, type) that will create an individual field in the table dbid with the specified label and type:
      async function addField(dbid, label, type) {
        return Promise.resolve(
          $.get(dbid, {
            act: "API_AddField",
            label,
            type
          })
        ).then(xml => {
          return {
            label,
            type,
            fid: $("fid", xml).text()
          }
        
        });
      }
    It is called an async function because it will always return a promise which when the promise resolves will return the label, type and fid as an object. Async functions are used with another keyword named await which basically indicates where the function should temporarily suspend execution until the promise that is being awaited resolves.

    In our cases we don't want to create just a single field, we want to create one field for each element in the fields array. To do this task we will need to create another function addFields(dbid, fields):
      async function* addFields(dbid, fields) {
        for (const {label, type} of fields) {
          yield await addField(dbid, label, type);
        }
      }
    The type of function is called an async[chronous] generator and is adorned with an asterisk (ie *) after the function keyword and uses the yield keyword within the function body. The yield keyword basically indicates where the generator will pause execution and yields its value to the body of the eventual for loop we will be using to perform the ultimate iteration.

    Your head may be exploding at this point at the complexity of this script and the number of new constructs being introduced. Fear not, because this construction allows us to iterate over the promises (which create new fields using API_AddField) with utter simplicity:
    for await (const {label, type, fid} of addFields(dbidRecords, fields)) {
      console.log('${label}, ${type}, ${fid}');
    }
    What this new for loop construct does is first call addFields(dbidRecords, fields) to return an object called an iterator and then proceeds to loop through the iterator and return the label, type and fid of the newly created field on each iteration of the iterator.

    Put it all together with a little additional boilerplate code and you have a general purpose method to create an arbitrary number of new fields of the specified type.

    Pastie Database
    https://haversineconsulting.quickbase.com/db/bgcwm2m4g?a=dr&rid=690

    Notes:

    (1) ...