Lesson 1B
Code Page Here - PeoplePage_rest.htmlRead Records with the REST API
Query the same Quickbase People table using the modern JSON REST API while keeping the table, fields, sorting, and rendered result equivalent to Lesson 1A.
Lesson Objective
Lesson 1A established how Quickbase tables and fields are represented in API code. Lesson 1B deliberately keeps those same Quickbase objects and changes only the API architecture.
The important question is no longer simply, “How do I query the People table?”
The question is: how does the modern Quickbase REST API represent the same table, fields, authorization, query, records, and values?
A Controlled Comparison
Lesson 1B uses the exact same Quickbase People table as Lesson 1A. That gives us a controlled comparison between the two APIs.
| Object | Quickbase Identity | Value |
|---|---|---|
| Quickbase realm | Realm hostname | window.location.hostname |
| People table | Table DBID | TABLE_ID_HERE |
| Record ID# | Field ID | 3 |
| Name | Field ID | 6 |
| Age | Field ID | 7 |
| Favorite Color | Field ID | 8 |
1. Identify the Quickbase Realm
const REALM = window.location.hostname;This is our first new Quickbase reference compared with Lesson 1A. REST requests include the Quickbase realm hostname in theQB-Realm-Hostname header.
Because the working HTML file is a Quickbase Code Page,window.location.hostnameretrieves the hostname of the Quickbase realm currently hosting that page.
2. The Table DBID and Field IDs Do Not Change
const TABLE_DBID = "TABLE_ID_HERE";
const FIELD_IDS = {
recordId: 3,
name: 6,
age: 7,
favoriteColor: 8,
};XML and REST are different interfaces to Quickbase, but the underlying Quickbase objects have not changed.
This is one of the most important observations in the first two lessons: the API changed; the Quickbase identities did not.
3. Obtain Temporary REST Authorization
This is the largest architectural difference from our XML Code Page. Before querying records, the REST example obtains temporary authorization from Quickbase.
const response = await fetch(
`https://api.quickbase.com/v1/auth/temporary/${TABLE_DBID}`,
{
method: "GET",
credentials: "include",
headers: {
"QB-Realm-Hostname": REALM,
"QB-App-Token": APP_TOKEN,
},
},
);Notice how several Quickbase references converge in this one request.
| Code | Quickbase Purpose |
|---|---|
/auth/temporary/${TABLE_DBID} | Requests temporary authorization associated with the Quickbase table. |
credentials: "include" | Includes the current signed-in Quickbase browser session. |
QB-Realm-Hostname | Identifies the Quickbase realm. |
QB-App-Token | Supplies the Application Token required by this application. |
4. Read the Temporary Authorization
const data = await response.json();
if (!data.temporaryAuthorization) {
throw new Error(
"Quickbase did not return temporaryAuthorization."
);
}
return data.temporaryAuthorization;The temporary authorization returned by Quickbase becomes the credential for the next REST request.
Security Note
During our debugging we temporarily logged the returned token so we could prove that authorization worked. That was useful as a checkpoint, but the completed instructional code should never log the token.
5. Build the Quickbase JSON Query
const query = {
from: TABLE_DBID,
select: [
FIELD_IDS.recordId,
FIELD_IDS.name,
FIELD_IDS.age,
FIELD_IDS.favoriteColor,
],
sortBy: [
{
fieldId: FIELD_IDS.name,
order: "ASC",
},
],
};This JSON object performs essentially the same job as several XML elements from Lesson 1A.
from
Identifies the Quickbase table DBID.
select
Lists the Quickbase Field IDs to return.
sortBy
Specifies the Field ID and sort direction.
XML and REST: Same Request Intent
Lesson 1A — XML
<clist>3.6.7.8</clist>
<slist>6</slist>
<options>sortorder-A</options>Lesson 1B — REST
select: [3, 6, 7, 8],
sortBy: [
{
fieldId: 6,
order: "ASC",
},
]6. Send the Records Query
const response = await fetch(
"https://api.quickbase.com/v1/records/query",
{
method: "POST",
headers: {
"QB-Realm-Hostname": REALM,
Authorization:
`QB-TEMP-TOKEN ${temporaryToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(query),
},
);REST changes how the API operation itself is selected.
The XML API uses:
QUICKBASE-ACTION: API_DoQueryREST instead uses a purpose-specific endpoint:
POST https://api.quickbase.com/v1/records/query7. Quickbase Returns JSON Records
The returned record structure is fundamentally different from structured XML.
XML
<record>
<f id="3">1</f>
<f id="6">Alice</f>
<f id="7">32</f>
<f id="8">Blue</f>
</record>REST JSON
{
"3": { "value": 1 },
"6": { "value": "Alice" },
"7": { "value": 32 },
"8": { "value": "Blue" }
}The representation changed, but Field ID 6 still means the Name field.
8. Read a REST Field Value
function getFieldValue(record, fieldId) {
return record[String(fieldId)]?.value ?? "";
}For the Name field:
9. The Record Collection Lives in data.data
const data = await response.json();
renderRecords(data.data);Our debugging checkpoints were useful here. The REST request had already succeeded before the table rendered correctly. Inspecting the complete response and then the first record established where the records actually lived and what each record looked like.
10. XML vs REST Side by Side
| Concept | Lesson 1A XML | Lesson 1B REST |
|---|---|---|
| API style | Legacy XML API | RESTful API |
| Query endpoint | /db/{TABLE_DBID} | https://api.quickbase.com/v1/records/query |
| API operation | QUICKBASE-ACTION: API_DoQuery | Endpoint determines the operation |
| Request data | <qdbapi> XML | JSON object |
| Requested fields | <clist>3.6.7.8</clist> | select: [3, 6, 7, 8] |
| Sorting | <slist>6</slist> + sortorder-A | sortBy: [{ fieldId: 6, order: "ASC" }] |
| Response parsing | response.text() + DOMParser | response.json() |
| Returned field | <f id="6">Alice</f> | "6": { "value": "Alice" } |
| Read field value | querySelector('f[id="6"]') | record["6"].value |
11. Our XML vs REST Timing Experiment
We added the same overall timer to both Code Pages:
const startTime = performance.now();
// Quickbase request and rendering
const endTime = performance.now();
const renderTime = endTime - startTime;In our tests, the XML Code Page was running more than twice as fast as the REST version. That is a valid observation, but it does not prove that XML parsing is faster than JSON parsing.
Lesson 1A XML
Lesson 1B REST
What We Can Actually Conclude
For this Code Page implementation and very small People dataset, obtaining a new temporary REST authorization before every records query adds another network operation. Therefore our total timer is measuring more work on the REST side than on the XML side.
With only six records, network and authorization latency can easily dominate the cost of parsing XML or JSON. Our training log correctly identified this distinction before drawing conclusions about the APIs themselves.
12. The Complete REST Request Path
Commented Quickbase Source
This source concentrates the comments on Quickbase behavior rather than ordinary JavaScript and DOM manipulation. The Application Token has intentionally been replaced with a placeholder.
/*
* ============================================================
* QUICKBASE REALM
* ============================================================
*
* A Quickbase REST request must identify the Quickbase realm.
*
* Because this Code Page is running inside Quickbase,
* window.location.hostname gives us the current realm hostname.
*/
const REALM = window.location.hostname;
/*
* ============================================================
* QUICKBASE TABLE DBID
* ============================================================
*
* The visible table name is "People", but REST API requests
* identify the table using its DBID.
*/
const TABLE_DBID = "TABLE_ID_HERE";
/*
* ============================================================
* QUICKBASE APPLICATION TOKEN
* ============================================================
*
* This application requires an Application Token.
*
* Do not place a Quickbase User Token in browser JavaScript.
*/
const APP_TOKEN = "YOUR_APPLICATION_TOKEN";
/*
* ============================================================
* QUICKBASE FIELD IDs
* ============================================================
*
* The JavaScript property names are chosen by us.
* The numbers are the actual Quickbase Field IDs.
*/
const FIELD_IDS = {
recordId: 3,
name: 6,
age: 7,
favoriteColor: 8,
};
/*
* ============================================================
* TEMPORARY REST AUTHORIZATION
* ============================================================
*
* Unlike our XML example, the REST Code Page first obtains
* temporary REST authorization.
*
* TABLE_DBID is included in the authorization endpoint.
*/
async function getTemporaryToken() {
const response = await fetch(
`https://api.quickbase.com/v1/auth/temporary/${TABLE_DBID}`,
{
method: "GET",
/*
* Include the signed-in Quickbase browser session.
*/
credentials: "include",
headers: {
/*
* Tell Quickbase which realm this request belongs to.
*/
"QB-Realm-Hostname": REALM,
/*
* Supply the Application Token required by this app.
*/
"QB-App-Token": APP_TOKEN,
},
},
);
/*
* REST responses are JSON.
*/
const data = await response.json();
if (!response.ok) {
throw new Error(
`HTTP ${response.status}: ${JSON.stringify(data)}`
);
}
/*
* The successful response must contain the temporary
* authorization value needed for the REST query.
*/
if (!data.temporaryAuthorization) {
throw new Error(
"Quickbase did not return temporaryAuthorization."
);
}
/*
* Never console.log() this token in finished code.
*/
return data.temporaryAuthorization;
}
/*
* ============================================================
* READING A QUICKBASE REST FIELD
* ============================================================
*
* A REST record uses the Quickbase Field ID as a JSON property.
*
* Simplified example:
*
* {
* "3": { "value": 1 },
* "6": { "value": "Alice" },
* "7": { "value": 32 },
* "8": { "value": "Blue" }
* }
*
* If fieldId is 6:
*
* record[String(fieldId)]
*
* becomes:
*
* record["6"]
*
* and .value returns the Quickbase field value.
*/
function getFieldValue(record, fieldId) {
return record[String(fieldId)]?.value ?? "";
}
async function loadPeople() {
/*
* Benchmark starts before REST authorization so the measured
* total includes the complete Code Page REST process.
*/
const startTime = performance.now();
const status = document.getElementById("status");
try {
/*
* ==========================================================
* STEP 1 — GET TEMPORARY QUICKBASE REST AUTHORIZATION
* ==========================================================
*/
const temporaryToken = await getTemporaryToken();
/*
* ==========================================================
* STEP 2 — BUILD THE QUICKBASE REST QUERY
* ==========================================================
*
* from:
* identifies the Quickbase table.
*
* select:
* specifies which Field IDs should be returned.
*
* sortBy:
* tells Quickbase to sort using Field ID 6 (Name)
* in ascending order.
*/
const query = {
from: TABLE_DBID,
select: [
FIELD_IDS.recordId,
FIELD_IDS.name,
FIELD_IDS.age,
FIELD_IDS.favoriteColor,
],
sortBy: [
{
fieldId: FIELD_IDS.name,
order: "ASC",
},
],
};
/*
* ==========================================================
* STEP 3 — QUERY QUICKBASE RECORDS
* ==========================================================
*/
const response = await fetch(
"https://api.quickbase.com/v1/records/query",
{
method: "POST",
headers: {
/*
* Identify the Quickbase realm.
*/
"QB-Realm-Hostname": REALM,
/*
* Authorize this REST request using the temporary
* token acquired in Step 1.
*/
Authorization:
`QB-TEMP-TOKEN ${temporaryToken}`,
/*
* The request body contains JSON.
*/
"Content-Type": "application/json",
},
/*
* Convert the JavaScript query object into JSON text.
*/
body: JSON.stringify(query),
},
);
/*
* Convert the REST JSON response into JavaScript objects.
*/
const data = await response.json();
if (!response.ok) {
throw new Error(
`HTTP ${response.status}: ${JSON.stringify(data)}`
);
}
/*
* ==========================================================
* QUICKBASE REST RECORD COLLECTION
* ==========================================================
*
* Returned records are located in:
*
* data.data
*
* Each item represents one Quickbase record.
*/
renderRecords(data.data);
/*
* Stop the timer after all records have been rendered.
*/
const endTime = performance.now();
const renderTime = endTime - startTime;
status.classList.remove("error");
status.textContent =
`REST query returned ${data.data.length} record(s) in ${renderTime.toFixed(2)} ms.`;
} catch (error) {
console.error(error);
status.classList.add("error");
status.textContent =
`REST query failed: ${error.message}`;
}
}
document.addEventListener(
"DOMContentLoaded",
loadPeople
);Lesson 1B Complete
You should now be able to identify the Quickbase realm, table DBID, Field IDs, Application Token, temporary authorization request, temporary REST token, JSON records query, REST response collection, and individual field values in a Quickbase REST Code Page.
More importantly, you should be able to look at Lessons 1A and 1B and recognize which pieces represent the same Quickbase objects even though XML and REST express them differently.