Quickbase Tutorials

Code Pages Developer Lab

A hands-on Quickbase API curriculum built from working Code Page examples.

Lesson 9

Code Page Here - QBSchemaExplorer.html

Quickbase 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
relationships

Lesson 10

JavaScript
    ↓
describes what to create
    ↓
Quickbase
    ↓
new tables
new fields
new relationships

First 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

1

Discover the App DBID

Read the Quickbase Code Page URL instead of hard-coding the application.

2

Ask Quickbase for its tables

Use the discovered App DBID with GET /v1/tables.

3

Build a dynamic table selector

Turn Quickbase's table response into choices the developer can select.

4

Resolve the selected Table DBID

Read the table selection only when an inspection action actually occurs.

5

Inspect table, field, and relationship schema

Use different REST endpoints to ask Quickbase about different parts of the structure.

6

Preserve the raw JSON

Study exactly what Quickbase returns before transforming it into another structure.

1

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 DBID

Beginner Trap #1

App DBID and Table DBID Are Not the Same Identifier

IdentifierIdentifiesExample
App DBIDThe Quickbase applicationbv3asij6q
Table DBIDOne table inside the applicationTABLE_ID_HERE
2

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
3

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..." forever

The selected Table DBID belongs inside the button action, when a real selection exists.

4

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=15

Discovered App DBID

beqbhappylol

Simulated REST Request #1

GET /v1/tables/bqpeople1?appId=beqbhappylol

Table 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.

Raw JSON Response
{
  "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"
}
5

Inspect Three Different Layers of Schema

ActionEndpointQuestion
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}/relationshipsHow 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

SymptomLikely LayerActual Lesson 9 Example
HTTP 400Request parametersRequired appId missing.
HTTP 401AuthorizationInvalid authorization for the request.
Loading tables foreverJavaScript startupSelection read before the dropdown existed.
ReferenceErrorJavaScript variable scopeOld TABLE_DBID reference remained after making the page dynamic.
6

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 visible

Lesson 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 schema

Next: 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.