Lesson 9
Code Page Here - QBSchemaExplorer.htmlQuickbase Schema Discovery
Before JavaScript can create tables, fields, and relationships dynamically, it helps to understand how Quickbase describes those same objects through the REST API.
Precursor to Lesson 10
First Discover What Exists. Then Learn How to Create It.
Lesson 9
Quickbase
↓
describes application
↓
JavaScript
↓
tables
fields
relationshipsLesson 10
JavaScript
↓
describes what to create
↓
Quickbase
↓
new tables
new fields
new relationshipsFirst Concept
Records Are Data. Schema Describes the Structure Holding the Data.
Earlier lessons concentrated on People records. The Schema Explorer asks different questions. Instead of asking Quickbase "which People records exist?", we ask it to describe the application itself.
Record Data
Record ID# 14 Name: Walter Age: 45 Favorite Color: Orange
Values stored inside a table.
Schema
Table: People Table DBID: bqpeople1 Key Field ID: 3 Fields: 3 → Record ID# 6 → Name 7 → Age 8 → Favorite Color
Information describing how the table is constructed.
Lesson 9 Roadmap
Six Steps from Code Page to Universal Schema Explorer
Discover the App DBID
Read the Quickbase Code Page URL instead of hard-coding the application.
Ask Quickbase for its tables
Use the discovered App DBID with GET /v1/tables.
Build a dynamic table selector
Turn Quickbase's table response into choices the developer can select.
Resolve the selected Table DBID
Read the table selection only when an inspection action actually occurs.
Inspect table, field, and relationship schema
Use different REST endpoints to ask Quickbase about different parts of the structure.
Preserve the raw JSON
Study exactly what Quickbase returns before transforming it into another structure.
Discover the App DBID from the Code Page URL
Earlier lessons could safely hard-code a single People table because they were teaching one known table. A reusable schema tool cannot make that assumption.
function getAppDbid() {
const match =
window.location.pathname.match(
/\/db\/([^/]+)/,
);
if (!match) {
throw new Error(
"Could not determine the App DBID " +
"from the Quickbase URL.",
);
}
return match[1];
}
const APP_DBID = getAppDbid();/db/bv3asij6q?a=dbpage&pageID=15
└───────┘
App DBIDBeginner Trap #1
App DBID and Table DBID Are Not the Same Identifier
| Identifier | Identifies | Example |
|---|---|---|
| App DBID | The Quickbase application | bv3asij6q |
| Table DBID | One table inside the application | TABLE_ID_HERE |
Ask the Application Which Tables Exist
Once the App DBID is known, the Explorer can ask Quickbase for the tables belonging to that application.
const endpoint =
`https://api.quickbase.com/v1/tables?appId=${APP_DBID}`;The appId query parameter is required.
During development, omitting it produced the HTTP 400 response:
Required query 'appId' not found
Build the Table Selector from Quickbase
Quickbase returns an array of table descriptions. JavaScript creates one option for every returned table.
tableSelect.replaceChildren();
for (const table of data) {
const option =
document.createElement("option");
option.value = table.id;
option.textContent =
`${table.name} — ${table.id}`;
tableSelect.appendChild(option);
}The Code Page therefore does not need to know beforehand whether the application contains People, Orders, Tasks, Intake Assessments, or anything else.
Beginner Trap #2
Do Not Ask for the Selected Table Before the Selector Has Been Populated
One development version called getSelectedTableDbid() at the top level of the script. At that moment the selector still contained only "Loading tables...".
SCRIPT STARTS
↓
getSelectedTableDbid()
↓
<select> is still empty
↓
throw Error(...)
↓
JavaScript stops
↓
DOMContentLoaded never gets wired
↓
getTables() never runs
↓
"Loading tables..." foreverThe selected Table DBID belongs inside the button action, when a real selection exists.
Resolve the Selected Table Only When It Is Needed
function getSelectedTableDbid() {
const tableSelect =
document.getElementById(
"tableSelect",
);
const tableDbid =
tableSelect.value;
if (!tableDbid) {
throw new Error(
"Select a Quickbase table first.",
);
}
return tableDbid;
}Then each inspection function obtains the current selection independently:
async function getFields() {
const tableDbid =
getSelectedTableDbid();
...
}Interactive Schema Explorer
Explore a Simulated Quickbase Application
This training version uses fake schema data locally. It mirrors the interaction of the working Code Page without making a live Quickbase request.
Simulated Code Page URL
/db/beqbhappylol?a=dbpage&pageID=15Discovered App DBID
beqbhappylolSimulated REST Request #1
GET /v1/tables/bqpeople1?appId=beqbhappylolTable Schema
Name, DBID, key field, aliases, sort settings, and table properties.
Fields
Field IDs, labels, types, modes, and properties.
Relationships
Parent table, child table, foreign key, lookups, and summaries.
{
"id": "bqpeople1",
"name": "People",
"alias": "_dbid_people",
"description": "People used throughout the Developer Lab.",
"created": "2026-08-01T13:00:00Z",
"updated": "2026-08-14T14:30:00Z",
"nextRecordId": 18,
"nextFieldId": 12,
"defaultSortFieldId": 6,
"defaultSortOrder": "ASC",
"keyFieldId": 3,
"singleRecordName": "Person",
"pluralRecordName": "People"
}Inspect Three Different Layers of Schema
| Action | Endpoint | Question |
|---|---|---|
| Get Table | /tables/{tableId}?appId={appId} | How is this table configured? |
| Get Fields | /fields?tableId={tableId} | What fields exist in this table? |
| Get Relationships | /tables/{tableId}/relationships | How is this child table related to other tables? |
Beginner Trap #3
A Correct Endpoint Can Still Fail Because Authorization Is Wrong
During development, the table endpoint was syntactically correct and still returned HTTP 401:
{
"message": "Unauthorized",
"description": "Invalid Authorization."
}This is why API debugging must separate endpoint construction from authentication. A 400, 401, and JavaScript ReferenceError point to very different layers of the program.
Debugging Guide from the Actual Build
The Error Message Tells You Which Layer to Investigate
| Symptom | Likely Layer | Actual Lesson 9 Example |
|---|---|---|
| HTTP 400 | Request parameters | Required appId missing. |
| HTTP 401 | Authorization | Invalid authorization for the request. |
| Loading tables forever | JavaScript startup | Selection read before the dropdown existed. |
| ReferenceError | JavaScript variable scope | Old TABLE_DBID reference remained after making the page dynamic. |
Preserve the Raw JSON First
The finished Explorer deliberately does not transform the schema response into custom tables or diagrams. It displays exactly what Quickbase returned.
const data =
await response.json();
output.textContent =
JSON.stringify(
data,
null,
2,
);Why raw JSON?
Before writing code that creates relationships, we need to understand the property names and identifiers Quickbase uses to describe existing relationships. Transformation can come later.
Preparing for Relationships
Relationship JSON Gives Lesson 10 Its Vocabulary
Quickbase's relationship response describes the parent table, child table, foreign key field, lookup fields, summary fields, and whether the relationship crosses applications.
Relationship ├── parentTableId ├── childTableId ├── foreignKeyField ├── lookupFields ├── summaryFields └── isCrossApp
Those names are about to become much more consequential when JavaScript starts telling Quickbase what relationship to create.
The Big Upgrade
We Removed the Hard-Coded Application Structure
Quickbase Code Page starts
↓
Discover App DBID from URL
↓
GET /tables?appId=...
↓
Quickbase returns table list
↓
Build table dropdown
↓
Developer selects table
↓
Read selected Table DBID
/ | \
/ | \
↓ ↓ ↓
Table Fields Relationships
Schema Schema Schema
\ | /
\ | /
└── Raw JSON ─────┘What “Universal” Means Here
The Explorer dynamically discovers the Quickbase application and its tables, so the same Code Page can inspect different apps without hard-coded App or Table DBIDs. The user still needs appropriate Quickbase permissions, temporary REST authorization must work in that environment, and an application token may still be required by the app's configuration.
Complete Schema Discovery Flow
DISCOVER → ENUMERATE → SELECT → INSPECT
Code Page opens
↓
getAppDbid()
↓
APP_DBID
↓
getTemporaryToken(APP_DBID)
↓
GET /v1/tables?appId=APP_DBID
↓
Quickbase returns tables
↓
Populate dropdown
↓
Developer selects table
↓
getSelectedTableDbid()
↓
TABLE_DBID
↓
Choose inspection
↓
┌─────────────────────────┐
│ GET TABLE │
│ GET FIELDS │
│ GET RELATIONSHIPS │
└─────────────────────────┘
↓
Quickbase returns schema
↓
JSON.stringify(data, null, 2)
↓
Raw schema visibleLesson 9 Complete
We Can Now Ask Quickbase What an Application Is Made Of
The Schema Explorer discovers its application, retrieves its tables, dynamically selects a table, and inspects table, field, and relationship metadata without depending on a hard-coded table structure.
LESSON 9
Quickbase
↓
"What already exists?"
↓
JavaScript understands schema
LESSON 10
JavaScript
↓
"Create this structure."
↓
Quickbase builds schemaNext: Lesson 10 — Creating Tables, Fields, and Relationships
Now that we understand how Quickbase describes application structure, we can begin sending schema instructions in the opposite direction.