SlideShare a Scribd company logo
Database abstraction – GoogleApps Script
Desktop liberation
Google Apps Script libraries providing a
noSQL API for a variety of backends
Provides reusability and transportability of
code between databases, and simplified
migration between them
SimpleAPI to learn, with the most common
capabilities exposed and standardized
A consistent results structure
Locking, backing off , caching, authentication
and limits handled transparently
With dbAbstraction, noSQL queries are the same for all
supported backend stores. So far this includes
scriptdb
Parse.com
Fusion
Orchestrate.io
Fusion
Sheets
Import.io (readonly)
Drive
Properties
DataStore
MongoDB
A web app that exposes the GAS dbab as a
JSON rest API
Handles POST and GET queries, updates,
inserts, gets, count and removes
Exposes all dbab capabilities
Oauth2 is mandatory to authenticate to the
webapp
Authentication credentials for backend
databases are securely stored in your copy of
its property store
cDataHandler
library
cEzyOauth2
library
cCacheHandler
library
Dbab webapp
App template
Your property
store
Backend driver
Backend
database
cFlattener
library
noSQL queries
Access token
Google oauth2
infrastructure
Query caching
cNamedLock
library
Transaction locking
JSON API
Query translation
authentication
Cloud
credentials
Access & refresh tokens
(un)Flatten objects
Your client
Oauth2
authentication
JSON REST API
You authenticate to dbab via oAuth2 using
Drive scope
Your published copy of dbab webapp already
has your various authentication properties
built in for your supported databases
If the backend database needs oauth2, that’s
also handled by the dbab JSON api
It’s a REST API that returns either JSON or JSONP. GET or POST is
supported for all actions.
action=query|remove|save|update|get
query= some noSQL query, the same syntax as the regular GAS
API
params = some params (skip|limit|sort) as the regular GAS API
driver=scriptdb|mongolab|sheet|drive|orchestrate|parse|datastore
|fusion (any exposed backend)
nocache=0|1 (use cache/don’t)
siloid= roughly equivalent to a table name
dbid = roughly equivalent to a database name
driverid=0|1 (whether to include driver generated ids in response)
callback=some callback – ask for jsonp rather than json
Same format as the GAS API
{
handleCode: 0, // +ve number= good, -ve bad
handleError:’’, //’some text about an error’
data:[], // the results
driverIds:[], // if asked for, any keys the driver generates automatically
handlerIds:[] // if asked for, the key the driver considers to be the unique
key for each data item
+ various other informational properties about handler version etc…
}
Now it’s simple to write an API for another
language that looks like the standard GASAPI
GAS dbab handles the translation to various
backends, with new features and new supported
drivers immediately available
Your API just needs to know how to talk to the
GAS dbab JSONAPI
You can centralize your various credentials in the
cloud, protected by oauth2
Your code can look very similar to the same code
using the GAS API directly (language syntax
constraints aside)
• Gets handler, creates nosql directives, deals with
responsesVBA application
• Deals with oauth2 authentication to your web app.
Translates directives to JSON API requests and handles
responses
VBA API
• Deals with requests and responses
Dbab GAS REST API
• deals with authentication credentials, caching. Gets
handler and interprets nosql queriesDbab GAS API
• Translates nosql queries to backend syntax and handles,
authentication, locking, responses and requestsDbab GAS driver
• Handles queries and returns data and responses to its
driverVarious backends
Oauth2 integration withVBA is covered
elsewhere in detail
Create an application in Google Cloud
Console
If usingVBA
 Do a one off registration to yourWindows registry
 From now on you can simply do this to get
authorized
Set oauth2 = getGoogled("drive")
Copy from this template
Add any credentials needed for any backend
as described here
Save a version and publish as a webapp – (set
to run as “user accessing the webapp”)
Take a note of the webapp URL
Run doGet to authorize it
If needed, run the web app once with
?driver=datastore to provoke setting up of
the refresh token structure
Do any setup needed to create your
databases or sheets you are using as a
backend
You can now access your webapp as a REST
API to talk to the supported backends
If you want to use theVBA API, continue to
step 4
Get emptycdataset.xlsm from desktop
liberation downloads
Set up your handler and web app URL
Set handler = New cDbAb
handler.setOauth2(oauth2).setEndPoint (_
"https://script.google.com/macros/s/xxxxxx/exec")
Set up your database type name, database
and data silo
handler.setDbName("sheet") _
.setDbId(“xxxx") _
.setSiloId(“yyyy”)
You can start…
I’ve tried to keep theVBA syntax is as close to original
Google Apps Script as possible within the limitations
of the language.
VBA has no native JavaScript like objects or JSON, but
I use cJobject throughout
The cJobject JSON parser allows both single and
double quotes to be used in JSON eg.
{‘name’:’ethel’}
can be used so it can more be easily represented as aVBA string
“{‘name’:’ethel’}”
cDataset can be used to write and read excel
workbooks to and from JSON
Code What it does
Set result = handler.remove() Removes everything from the handler’s silo
Set result = handler.save(testData) Saves data in the given cJObject.You can
easily create a cJobject from an Excel sheet
like this
Set ds = New cDataSet
Set testData = ds.load("dbab").jObject(, , , ,
"data")
Set result = handler.query() Get everything in the handler’s silo
Set result = handler.query(, "{'limit':2}") Get the first 2 objects. Note that both single
quotes and double quotes are allowed by
this JSONParser to make it easier to enter
JSON as aVBA string
Set result = handler.query(, "{'sort':'-name'}") Get everything in the handler’s silo, sorted in
reverse order using the property ‘name’
Code What it does
Set result = handler.query(, "{'sort':'-
name','skip':3}")
Sort by name and skip the first 3
Set result = handler.query("{'name':'ethel'}") Select all objects whose name is ‘ethel’
Set result = handler.query(
("{'stuff':{'sex':'female'}}")
Select all objects where stuff.sex = ‘female’
Set result = handler.query(
("{'stuff.sex':'female'}")
Same as above. Note that you can use either
deep or flattened objects for both data and
queries. Regardless of how the driver has to
store the data (for example two dimensional
backends like sheets need to store flattened
data), the result of the query will be natural,
unflattened objects
Code What it does
Set result =
handler.query("{'stuff.sex':'male'}", , 1, 1)
Select all objects where name is john or
mary and stuff.sex is male, don’t use cache,
and return the unique keys recognized by
the driver for each object as well
handler.update(result.handleKeys, data) Replace all the objects with the keys
returned from the previous query with new
data
handler.remove("{'stuff.sex':'male'}") Remove all the objects where stuff.sex is
male
Set r2 =
handler.getObjects(result.handleKeys)
Get all the objects whose keys were
returned by a previous query
Code What it does
Set result = handler.query("{'name':" &
handler.constraints("[['IN',['ethel','fred']]]")
& "}"
Note that queries other than equality, need
constraints. Unfortunately the syntax is a bit
fiddly to construct as aVBA string.The
function handler.constraints() converts your
query into consumable syntax for the API.
This query selects all objects whose name is
in the given list
handler.query("{'stuff.age':" &
handler.constraints("[['GT',25],['LTE',60]]") &
"}")
Select all objects where stuff.age > 25 and
<= 60
handler.query("{'stuff':{'age':" &
handler.constraints("[['GT',25]]") & "}}")
Select all objects where stuff.age > 25
"{'stuff':{'sex':'male', 'age':" &
handler.constraints("[['GTE',25],['LT',60]]") &
"}}"
Select all objects where stuff.sex = ‘male’
and age is >= 25 and < 60
Code What it does
handler.query( "{'name':" &
handler.constraints("[['IN',['john','mary']]]")
& ",'stuff.sex':'male','stuff.age':" &
handler.constraints("[['GT',25]]") & "}"
Select all objects where name is john or
mary and stuff.sex is male and stuff,age > 25
handler.query("{'stuff.age':" &
handler.constraints("[['GT',25],['LTE',60]]") &
"}")
Select all objects where stuff.age > 25 and
<= 60
handler.query( "{'stuff.age':" &
handler.constraints("[['GT',25]]") & "}",
"{'limit':1}“)
Select the first object where stuff.age > 25
handler.query( "{'stuff':{'sex':'male', 'age':" &
handler.constraints("[['GTE',25],['LT',60]]") &
"}}“)
Select all objects where stuff.sex = ‘male’
and age is >= 25 and < 60
It’s simple to copy the database contents to a
worksheet
Do a query
Construct a sheet
Set result = handler.query()
Set ds = makeSheetFromJob(result.data, “yoursheetname”)
Since an excel sheet is two dimensional, any
deep objects will be flattened to dot syntax
so they can be represented as an excel table
It’s simple to copy the worksheet contents to a
database
Load the sheet and convert it to JSON
Save to your selected back end
Set testData = ds.load(“yoursheetname”).jObject(, , , , "data")
Set result = handler.save(testData)
Any flattened objects will be automatically
converted back to deep objects
Read about Google Apps Script data
abstraction here.
Read about the dbab JSONAPI here
Read about theVBA API client here.
Read about ezyOauth2 here.
Contact me on google plus or at my forum
and share with others how you are using this
API
Join the Google Apps Script Community

More Related Content

PDF
JavaScript client API for Google Apps Script API primer
PPTX
Dbabstraction
PPTX
Google cloud datastore driver for Google Apps Script DB abstraction
PDF
Do something useful in Apps Script 5. Get your analytics pageviews to a sprea...
PDF
Do something in 5 with gas 4- Get your analytics profiles to a spreadsheet
PDF
Do something in 5 with gas 3-simple invoicing app
PPTX
Goa tutorial
PDF
Do something in 5 with gas 8-copy between databases
JavaScript client API for Google Apps Script API primer
Dbabstraction
Google cloud datastore driver for Google Apps Script DB abstraction
Do something useful in Apps Script 5. Get your analytics pageviews to a sprea...
Do something in 5 with gas 4- Get your analytics profiles to a spreadsheet
Do something in 5 with gas 3-simple invoicing app
Goa tutorial
Do something in 5 with gas 8-copy between databases

What's hot (20)

PDF
VBA API for scriptDB primer
PDF
Do something in 5 with gas 9-copy between databases with oauth2
PDF
Do something in 5 with apps scripts number 6 - fusion crossfilter
PDF
Using script db as a deaddrop to pass data between GAS, JS and Excel
PPTX
MongoDB - Aggregation Pipeline
PDF
Lazy evaluation drupal camp moscow 2014
DOC
Database c# connetion
PPTX
Angular JS deep dive
PPTX
Using Cerberus and PySpark to validate semi-structured datasets
PPTX
MongoDB Aggregation
PPTX
Html indexed db
PDF
PDF
Testowanie JavaScript
PPTX
Leveraging Azure Search in Your Application
PDF
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
PDF
Building data flows with Celery and SQLAlchemy
PPT
Introduction to MongoDB
PDF
Improving Performance and Flexibility of Content Listings Using Criteria API
PDF
Streaming using Kafka Flink & Elasticsearch
TXT
Bulk copy
VBA API for scriptDB primer
Do something in 5 with gas 9-copy between databases with oauth2
Do something in 5 with apps scripts number 6 - fusion crossfilter
Using script db as a deaddrop to pass data between GAS, JS and Excel
MongoDB - Aggregation Pipeline
Lazy evaluation drupal camp moscow 2014
Database c# connetion
Angular JS deep dive
Using Cerberus and PySpark to validate semi-structured datasets
MongoDB Aggregation
Html indexed db
Testowanie JavaScript
Leveraging Azure Search in Your Application
MongoDB .local Toronto 2019: Using Change Streams to Keep Up with Your Data
Building data flows with Celery and SQLAlchemy
Introduction to MongoDB
Improving Performance and Flexibility of Content Listings Using Criteria API
Streaming using Kafka Flink & Elasticsearch
Bulk copy
Ad

Similar to Google apps script database abstraction exposed version (20)

PDF
Google App Engine With Java And Groovy
PDF
AWS IoT 핸즈온 워크샵 - 실습 5. DynamoDB에 센서 데이터 저장하기 (김무현 솔루션즈 아키텍트)
PDF
Local data storage for mobile apps
PPT
Play!ng with scala
PDF
Parse cloud code
PDF
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
PDF
Amazon Web Services for PHP Developers
PDF
9 Python programming notes for ktu physics and computer application semester 4
PDF
OSGi and Spring Data for simple (Web) Application Development - Christian Bar...
PDF
OSGi and Spring Data for simple (Web) Application Development
PPTX
Dev Jumpstart: Build Your First App with MongoDB
PDF
Local storage in Web apps
PDF
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
PDF
Data models in Angular 1 & 2
PPTX
Serverless archtiectures
PDF
Getting started with node JS
ODP
An Overview of Node.js
PDF
Ajax Performance Tuning and Best Practices
PDF
ETL With Cassandra Streaming Bulk Loading
PDF
mongodb-introduction
Google App Engine With Java And Groovy
AWS IoT 핸즈온 워크샵 - 실습 5. DynamoDB에 센서 데이터 저장하기 (김무현 솔루션즈 아키텍트)
Local data storage for mobile apps
Play!ng with scala
Parse cloud code
Finding the right stuff, an intro to Elasticsearch (at Rug::B)
Amazon Web Services for PHP Developers
9 Python programming notes for ktu physics and computer application semester 4
OSGi and Spring Data for simple (Web) Application Development - Christian Bar...
OSGi and Spring Data for simple (Web) Application Development
Dev Jumpstart: Build Your First App with MongoDB
Local storage in Web apps
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
Data models in Angular 1 & 2
Serverless archtiectures
Getting started with node JS
An Overview of Node.js
Ajax Performance Tuning and Best Practices
ETL With Cassandra Streaming Bulk Loading
mongodb-introduction
Ad

Recently uploaded (20)

PPTX
MODULE 8 - DISASTER risk PREPAREDNESS.pptx
PPTX
iec ppt-1 pptx icmr ppt on rehabilitation.pptx
PDF
168300704-gasification-ppt.pdfhghhhsjsjhsuxush
PDF
Capcut Pro Crack For PC Latest Version {Fully Unlocked 2025}
PPTX
Introduction to Firewall Analytics - Interfirewall and Transfirewall.pptx
PPTX
Microsoft-Fabric-Unifying-Analytics-for-the-Modern-Enterprise Solution.pptx
PPTX
Qualitative Qantitative and Mixed Methods.pptx
PPTX
The THESIS FINAL-DEFENSE-PRESENTATION.pptx
PPTX
modul_python (1).pptx for professional and student
PPTX
Managing Community Partner Relationships
PDF
.pdf is not working space design for the following data for the following dat...
PDF
Business Analytics and business intelligence.pdf
PPT
Reliability_Chapter_ presentation 1221.5784
PDF
BF and FI - Blockchain, fintech and Financial Innovation Lesson 2.pdf
PPTX
SAP 2 completion done . PRESENTATION.pptx
PDF
Mega Projects Data Mega Projects Data
PDF
Galatica Smart Energy Infrastructure Startup Pitch Deck
PPTX
AI Strategy room jwfjksfksfjsjsjsjsjfsjfsj
PPTX
oil_refinery_comprehensive_20250804084928 (1).pptx
MODULE 8 - DISASTER risk PREPAREDNESS.pptx
iec ppt-1 pptx icmr ppt on rehabilitation.pptx
168300704-gasification-ppt.pdfhghhhsjsjhsuxush
Capcut Pro Crack For PC Latest Version {Fully Unlocked 2025}
Introduction to Firewall Analytics - Interfirewall and Transfirewall.pptx
Microsoft-Fabric-Unifying-Analytics-for-the-Modern-Enterprise Solution.pptx
Qualitative Qantitative and Mixed Methods.pptx
The THESIS FINAL-DEFENSE-PRESENTATION.pptx
modul_python (1).pptx for professional and student
Managing Community Partner Relationships
.pdf is not working space design for the following data for the following dat...
Business Analytics and business intelligence.pdf
Reliability_Chapter_ presentation 1221.5784
BF and FI - Blockchain, fintech and Financial Innovation Lesson 2.pdf
SAP 2 completion done . PRESENTATION.pptx
Mega Projects Data Mega Projects Data
Galatica Smart Energy Infrastructure Startup Pitch Deck
AI Strategy room jwfjksfksfjsjsjsjsjfsjfsj
oil_refinery_comprehensive_20250804084928 (1).pptx

Google apps script database abstraction exposed version

  • 1. Database abstraction – GoogleApps Script Desktop liberation
  • 2. Google Apps Script libraries providing a noSQL API for a variety of backends Provides reusability and transportability of code between databases, and simplified migration between them SimpleAPI to learn, with the most common capabilities exposed and standardized A consistent results structure Locking, backing off , caching, authentication and limits handled transparently
  • 3. With dbAbstraction, noSQL queries are the same for all supported backend stores. So far this includes scriptdb Parse.com Fusion Orchestrate.io Fusion Sheets Import.io (readonly) Drive Properties DataStore MongoDB
  • 4. A web app that exposes the GAS dbab as a JSON rest API Handles POST and GET queries, updates, inserts, gets, count and removes Exposes all dbab capabilities Oauth2 is mandatory to authenticate to the webapp Authentication credentials for backend databases are securely stored in your copy of its property store
  • 5. cDataHandler library cEzyOauth2 library cCacheHandler library Dbab webapp App template Your property store Backend driver Backend database cFlattener library noSQL queries Access token Google oauth2 infrastructure Query caching cNamedLock library Transaction locking JSON API Query translation authentication Cloud credentials Access & refresh tokens (un)Flatten objects Your client Oauth2 authentication JSON REST API
  • 6. You authenticate to dbab via oAuth2 using Drive scope Your published copy of dbab webapp already has your various authentication properties built in for your supported databases If the backend database needs oauth2, that’s also handled by the dbab JSON api
  • 7. It’s a REST API that returns either JSON or JSONP. GET or POST is supported for all actions. action=query|remove|save|update|get query= some noSQL query, the same syntax as the regular GAS API params = some params (skip|limit|sort) as the regular GAS API driver=scriptdb|mongolab|sheet|drive|orchestrate|parse|datastore |fusion (any exposed backend) nocache=0|1 (use cache/don’t) siloid= roughly equivalent to a table name dbid = roughly equivalent to a database name driverid=0|1 (whether to include driver generated ids in response) callback=some callback – ask for jsonp rather than json
  • 8. Same format as the GAS API { handleCode: 0, // +ve number= good, -ve bad handleError:’’, //’some text about an error’ data:[], // the results driverIds:[], // if asked for, any keys the driver generates automatically handlerIds:[] // if asked for, the key the driver considers to be the unique key for each data item + various other informational properties about handler version etc… }
  • 9. Now it’s simple to write an API for another language that looks like the standard GASAPI GAS dbab handles the translation to various backends, with new features and new supported drivers immediately available Your API just needs to know how to talk to the GAS dbab JSONAPI You can centralize your various credentials in the cloud, protected by oauth2 Your code can look very similar to the same code using the GAS API directly (language syntax constraints aside)
  • 10. • Gets handler, creates nosql directives, deals with responsesVBA application • Deals with oauth2 authentication to your web app. Translates directives to JSON API requests and handles responses VBA API • Deals with requests and responses Dbab GAS REST API • deals with authentication credentials, caching. Gets handler and interprets nosql queriesDbab GAS API • Translates nosql queries to backend syntax and handles, authentication, locking, responses and requestsDbab GAS driver • Handles queries and returns data and responses to its driverVarious backends
  • 11. Oauth2 integration withVBA is covered elsewhere in detail Create an application in Google Cloud Console If usingVBA  Do a one off registration to yourWindows registry  From now on you can simply do this to get authorized Set oauth2 = getGoogled("drive")
  • 12. Copy from this template Add any credentials needed for any backend as described here Save a version and publish as a webapp – (set to run as “user accessing the webapp”) Take a note of the webapp URL Run doGet to authorize it If needed, run the web app once with ?driver=datastore to provoke setting up of the refresh token structure
  • 13. Do any setup needed to create your databases or sheets you are using as a backend You can now access your webapp as a REST API to talk to the supported backends If you want to use theVBA API, continue to step 4
  • 14. Get emptycdataset.xlsm from desktop liberation downloads Set up your handler and web app URL Set handler = New cDbAb handler.setOauth2(oauth2).setEndPoint (_ "https://script.google.com/macros/s/xxxxxx/exec") Set up your database type name, database and data silo handler.setDbName("sheet") _ .setDbId(“xxxx") _ .setSiloId(“yyyy”) You can start…
  • 15. I’ve tried to keep theVBA syntax is as close to original Google Apps Script as possible within the limitations of the language. VBA has no native JavaScript like objects or JSON, but I use cJobject throughout The cJobject JSON parser allows both single and double quotes to be used in JSON eg. {‘name’:’ethel’} can be used so it can more be easily represented as aVBA string “{‘name’:’ethel’}” cDataset can be used to write and read excel workbooks to and from JSON
  • 16. Code What it does Set result = handler.remove() Removes everything from the handler’s silo Set result = handler.save(testData) Saves data in the given cJObject.You can easily create a cJobject from an Excel sheet like this Set ds = New cDataSet Set testData = ds.load("dbab").jObject(, , , , "data") Set result = handler.query() Get everything in the handler’s silo Set result = handler.query(, "{'limit':2}") Get the first 2 objects. Note that both single quotes and double quotes are allowed by this JSONParser to make it easier to enter JSON as aVBA string Set result = handler.query(, "{'sort':'-name'}") Get everything in the handler’s silo, sorted in reverse order using the property ‘name’
  • 17. Code What it does Set result = handler.query(, "{'sort':'- name','skip':3}") Sort by name and skip the first 3 Set result = handler.query("{'name':'ethel'}") Select all objects whose name is ‘ethel’ Set result = handler.query( ("{'stuff':{'sex':'female'}}") Select all objects where stuff.sex = ‘female’ Set result = handler.query( ("{'stuff.sex':'female'}") Same as above. Note that you can use either deep or flattened objects for both data and queries. Regardless of how the driver has to store the data (for example two dimensional backends like sheets need to store flattened data), the result of the query will be natural, unflattened objects
  • 18. Code What it does Set result = handler.query("{'stuff.sex':'male'}", , 1, 1) Select all objects where name is john or mary and stuff.sex is male, don’t use cache, and return the unique keys recognized by the driver for each object as well handler.update(result.handleKeys, data) Replace all the objects with the keys returned from the previous query with new data handler.remove("{'stuff.sex':'male'}") Remove all the objects where stuff.sex is male Set r2 = handler.getObjects(result.handleKeys) Get all the objects whose keys were returned by a previous query
  • 19. Code What it does Set result = handler.query("{'name':" & handler.constraints("[['IN',['ethel','fred']]]") & "}" Note that queries other than equality, need constraints. Unfortunately the syntax is a bit fiddly to construct as aVBA string.The function handler.constraints() converts your query into consumable syntax for the API. This query selects all objects whose name is in the given list handler.query("{'stuff.age':" & handler.constraints("[['GT',25],['LTE',60]]") & "}") Select all objects where stuff.age > 25 and <= 60 handler.query("{'stuff':{'age':" & handler.constraints("[['GT',25]]") & "}}") Select all objects where stuff.age > 25 "{'stuff':{'sex':'male', 'age':" & handler.constraints("[['GTE',25],['LT',60]]") & "}}" Select all objects where stuff.sex = ‘male’ and age is >= 25 and < 60
  • 20. Code What it does handler.query( "{'name':" & handler.constraints("[['IN',['john','mary']]]") & ",'stuff.sex':'male','stuff.age':" & handler.constraints("[['GT',25]]") & "}" Select all objects where name is john or mary and stuff.sex is male and stuff,age > 25 handler.query("{'stuff.age':" & handler.constraints("[['GT',25],['LTE',60]]") & "}") Select all objects where stuff.age > 25 and <= 60 handler.query( "{'stuff.age':" & handler.constraints("[['GT',25]]") & "}", "{'limit':1}“) Select the first object where stuff.age > 25 handler.query( "{'stuff':{'sex':'male', 'age':" & handler.constraints("[['GTE',25],['LT',60]]") & "}}“) Select all objects where stuff.sex = ‘male’ and age is >= 25 and < 60
  • 21. It’s simple to copy the database contents to a worksheet Do a query Construct a sheet Set result = handler.query() Set ds = makeSheetFromJob(result.data, “yoursheetname”) Since an excel sheet is two dimensional, any deep objects will be flattened to dot syntax so they can be represented as an excel table
  • 22. It’s simple to copy the worksheet contents to a database Load the sheet and convert it to JSON Save to your selected back end Set testData = ds.load(“yoursheetname”).jObject(, , , , "data") Set result = handler.save(testData) Any flattened objects will be automatically converted back to deep objects
  • 23. Read about Google Apps Script data abstraction here. Read about the dbab JSONAPI here Read about theVBA API client here. Read about ezyOauth2 here. Contact me on google plus or at my forum and share with others how you are using this API Join the Google Apps Script Community