JD
The Startup
Published in
4 min readAug 6, 2020

--

Get AWS Honeycode Table UUIDs

While looking to keeping Amazon Honeycode in sync with database changes, I was fortunate enough to come across Ian Mckay’s project honeycode-appflow-integration where he demonstrated the calls he makes.

The Honeycode API is pretty locked down, and primarily based around ARNs and UUIDs. Fun stuff! Also their.. terminology.. between the UI and API appears to be pretty out of sync?

So for a user to get their table UUID, they would also need to know their workbook UUID, and rather then trying to explain how to parse this all out, I wrote a very ugly bit of code to query the API and provide it to you.

This has resulted in query-honeycode.

Workbook UUIDs

To get the Workbook UUIDs we need to accomplish the following:

  • Login to Honeycode and get an api token
  • Find out the Honeycode User ID
  • Retrieve our Drive ARN
  • Retrieve the list of Workbooks

API Token

Using Ian’s method of retrieving the API token, bluesky-api-token:

const loginReq = await fetch("https://bhauthngateway.us-east-1.honeycode.aws/v2/login", {
"headers": {
"accept": "application/json, text/plain, */*",
"content-type": "application/json;charset=UTF-8",
"origin": "https://builder.honeycode.aws"
},
"body": JSON.stringify({
"emailAddress": parameterLogin,
"password": parameterPassword
}),
"method": "POST",
"mode": "cors"
});

let apitoken = '';
for (let cookie of loginReq.headers.raw()['set-cookie']) {
if (cookie.startsWith("bluesky-api-token=")) {
apitoken = cookie.split("=")[1].split(";")[0];
}
}

Honeycode User ID

To get the list of workbooks, we need to include our userId in the call — odd when we have an API token. To do this we hit the logged-in-user-profile endpoint:

const loggedInUserReq = await fetch("https://bhauthngateway.us-east-1.honeycode.aws/v2/logged-in-user-profile", {
"headers": {
"accept": "*/*",
"content-encoding": "amz-1.0",
"content-type": "application/json",
"cookie": "bluesky-api-token=" + apitoken,
"origin": "https://builder.honeycode.aws"
},
"method": "GET",
"mode": "cors",
"credentials": "include"
});

const loggedInUserData = await loggedInUserReq.json();
const ownerId = loggedInUserData.userProfile.userId;

Drive ARN

So this is where we seem to start running into the terminology strangeness? We will pull the workbook ARN which appears to be our Drive ARN, i.e. our main dashboard.

const controlReq = await fetch("https://control.us-west-2.honeycode.aws/", {
"headers": {
"accept": "*/*",
"content-encoding": "amz-1.0",
"content-type": "application/json",
"x-amz-target": "com.amazon.sheets.control.api.SheetsControlServiceAPI_20170701.DescribeAttacheWorkbook",
"x-client-id": "clientRegion|BeehiveSDSJSUtils||||",
"cookie": "bluesky-api-token=" + apitoken,
"origin": "https://builder.honeycode.aws"
},
"body": JSON.stringify({"attacheWorkbookType": "user_attache", "ownerId": ownerId}),
"method": "POST",
"mode": "cors",
"credentials": "include"
});

const controlData = await controlReq.json();
const workbookArn = controlData.workbook;

Workbook ARN

So… we have the dashboard it appears, and it is made up of multiple tables. We need to get the list of tables, and identify the table which contains our workbooks. Then we need to query THAT table to get the list of workbooks and their associated ARNs.

The first step, lets get the list of tables:

const tableReq = await fetch("https://pod11.dp.us-west-2.honeycode.aws/external/", {
"headers": {
"accept": "*/*",
"content-encoding": "amz-1.0",
"content-type": "application/json",
"x-amz-target": "com.amazon.sheets.data.external.SheetsDataService.ListTables",
"x-client-id": "clientRegion|BeehiveSDSJSUtils||||",
"cookie": "bluesky-api-token=" + apitoken,
"origin": "https://builder.honeycode.aws"
},
"body": JSON.stringify({"workbookArn":workbookArn}),
"method": "POST",
"mode": "cors",
"credentials": "include"
});

const tableData = await tableReq.json();

Now the table we are interested in, that holds our workbooks, is AttacheAssetsTable:

var tableArn = "";

var rowCount = tableData.items.length;
for (var i=0; i< rowCount; i++) {
if(tableData.items[i].tableName === "AttacheAssetsTable") {
tableArn = tableData.items[i].tableArn;
}
}

Now with the appropriate table arn, we have to query it to find the contents:

const workbookReq = await fetch("https://pod11.dp.us-west-2.honeycode.aws/external/", {
"headers": {
"accept": "*/*",
"content-encoding": "amz-1.0",
"content-type": "application/json",
"x-amz-target": "com.amazon.sheets.data.external.SheetsDataService.QueryTableRowsByFilter",
"x-client-id": "clientRegion|BeehiveSDSJSUtils||||",
"cookie": "bluesky-api-token=" + apitoken,
"origin": "https://builder.honeycode.aws"
},
"body": JSON.stringify({"tableArn":tableArn}),
"method": "POST",
"mode": "cors",
"credentials": "include"
});

const workbookData = await workbookReq.json();

And now there is simply the joy of parsing this block of JSON. It appears that the name of the workbooks are in column 3, while the arns are in column 4… I couldn’t see any nice attribute that would simplify this process :(

Table ARNs

That was all the hard part, now that we have the Workbook ARN, we can pull the tables associated with it via:

const tableReq = await fetch("https://pod17.dp.us-west-2.honeycode.aws/external/", {
"headers": {
"accept": "*/*",
"content-encoding": "amz-1.0",
"content-type": "application/json",
"x-amz-target": "com.amazon.sheets.data.external.SheetsDataService.ListSheets",
"x-client-id": "clientRegion|BeehiveSDSJSUtils||||",
"cookie": "bluesky-api-token=" + apitoken,
"origin": "https://builder.honeycode.aws"
},
"body": JSON.stringify({includeSheetDetail: true, workbookArn: parameterWorkbookArn}),
"method": "POST",
"mode": "cors",
"credentials": "include"
});
const tableData = await tableReq.json();

Running the Script

Step one is to pull the workbooks:

$ npm install $ node index.js workbooks -u USERNAME -p "PASSWORD" Workbook Name	Workbook UUID
------------- -------------
Workbook1 arn:aws:sheets:us-west-2:1234567890:workbook:a132hkhk-i7yugy-ihijk--3f409c8fc35a

And then step two is to get the corresponding tables:

$ node index.js tables -u USERNAME -p "PASSWORD" -w "arn:aws:sheets:us-west-2:1234567890:workbook:a132hkhk-i7yugy-ihijk-3f409c8fc35a" Table Name    Table UUID 
------------- -------------
Table1 arn:aws:sheets:us-west-2:1234567890:sheet:a132hkhk-i7yugy-ihijk-3f409c8fc35a/b2cdc524-4085-352f-86b9-c7c956eb9da2
Table2 arn:aws:sheets:us-west-2:1234567890:sheet:a132hkhk-i7yugy-ihijk-3f409c8fc35a/aa71e742-1e32-4882-9f18-e45a7bb555dc
Table3 arn:aws:sheets:us-west-2:1234567890:sheet:a132hkhk-i7yugy-ihijk-3f409c8fc35a/a39790d1-e09b-48a8-9e97-5cf4c671f5e9

Note that there is zero error handling etc.. I’d throw it onto a To-Do list somewhere, but really hope they open the API up before then.

Originally published at https://gizmo.codes.

--

--