Quickbase Tutorials

Code Pages Developer Lab

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

Lesson 10

Code Page Here - DynamicSchema.html

Dynamic Quickbase Schema Creation

Create tables, fields, and relationships with the Quickbase REST API, capture the identifiers Quickbase returns, and observe the additional schema that Quickbase creates automatically.

← Review Lesson 9Working file: QBSchemaExplorer.html

Lesson Objective

Lesson 9 asked Quickbase to describe schema that already existed. Lesson 10 reverses that direction. JavaScript will now send schema instructions to Quickbase and progressively construct two new tables around the existing People training table.

Departments

Department Name

Location

People

Existing training table

Name

Age

Favorite Color

Tasks

Task Name

Due Date

Status

Departments → People → Tasks

Part 1

Where Lesson 9 Left Us

The Schema Explorer from Lesson 9 taught us how to discover the application's structure instead of hard-coding it. The Code Page could discover the current App DBID, retrieve the application's tables, inspect fields, find Field IDs, and inspect child-side relationship metadata.

Lesson 9

Quickbase
↓
REST API
↓
JavaScript
↓
Inspect existing schema

Lesson 10

JavaScript
↓
REST API
↓
Quickbase
↓
Create new schema

Aha Moment

Metadata becomes an input

Schema metadata is not useful only for documenting an application. Once JavaScript discovers a Table DBID or Field ID, that identifier can become an input to the next API request.

Part 2

Start With the Schema, Not the API

We do not begin by throwing POST requests at Quickbase. First, define the structure that the requests must eventually create.

Target schema
Departments
├── Department Name
└── Location
        │
        ▼
People
├── Name
├── Age
└── Favorite Color
        │
        ▼
Tasks
├── Task Name
├── Due Date
└── Status

The important question in this lesson is not merely what a parent or child table is. The important question is what Quickbase physically creates when JavaScript asks Quickbase to construct those relationships.

Part 3

Our API Requests Do Not Create Everything

Creating a Quickbase table is a higher-level schema operation. Quickbase automatically supplies its normal system fields before our code creates a single custom field.

Quickbase Creates Automatically

Date Created

Date Modified

Record ID#

Record Owner

Last Modified By

Our REST Requests Create

Department Name

Location

Relationships add a third provenance category. A relationship operation can cause Quickbase to add a reference field and lookup fields even though our JavaScript never sends separatePOST /fieldsrequests for them.

Departments → People relationship request
{
  parentTableId: departmentsTableDbid,

  foreignKeyField: {
    label: "Related Department"
  },

  lookupFieldIds: [
    departmentNameFieldId,
    departmentLocationFieldId
  ]
}

We explicitly created earlier

Department Name

Location

Quickbase creates for the relationship

Related Department

Department Name lookup

Location lookup

Aha Moment

One API request can produce several pieces of schema

Quickbase schema is not necessarily a one-to-one representation of your REST calls. One relationship request can cause Quickbase to create supporting fields needed to implement that relationship.

Part 4

Construction Order Matters

A relationship cannot be constructed before the identifiers it depends on exist. Dynamic schema creation therefore becomes a dependency chain between API requests and API responses.

Departments branch
Create Departments
        ↓
Capture Departments Table DBID
        ↓
Create Department Name
        ↓
Capture Field ID
        ↓
Create Location
        ↓
Capture Field ID
        ↓
Discover People Table DBID
        ↓
Create Departments → People
Tasks branch
Create Tasks
        ↓
Capture Tasks Table DBID
        ↓
Create Task Name
        ↓
Create Due Date
        ↓
Create Status
        ↓
Capture all Field IDs
        ↓
Discover People Name Field ID
        ↓
Create People → Tasks

Aha Moment

An API response becomes the next request's input

The important information from a successful request is often not simply "success." Quickbase returns identifiers that our next request requires.

Part 5

Never Guess an Identifier

During testing, a newly created table reported anextFieldIdvalue that let us predict what the next custom FIDs might be. The prediction happened to be correct.

That is useful for understanding Quickbase behavior. It is not how the application should obtain an identifier.

Do not predict
// Do not do this.
lessonState.departmentNameFieldId = 6;
Capture what Quickbase actually returned
const data = await response.json();

lessonState.departmentNameFieldId = data.id;

Aha Moment

Quickbase is authoritative

nextFieldId can help us understand what Quickbase may do next. It does not give JavaScript permission to manufacture the response before Quickbase returns it.

Part 6

Field IDs Are Local to Their Tables

One of the most useful discoveries in the finished schema was that different tables can legitimately contain the same Field ID.

TableFieldFID
DepartmentsDepartment Name6
PeopleName6
TasksTask Name6

There is no collision because a Field ID is meaningful in the context of its table. That is why the Code Page retains both Table DBIDs and Field IDs.

Departments / FID 6
People      / FID 6
Tasks       / FID 6

// Three different fields.

Part 7

The Lesson State Object

The Code Page keeps the identifiers it discovers and creates in a JavaScript object. This is more than convenient storage: it represents the dependencies between schema operations.

lessonState
const lessonState = {
  departmentsTableDbid: null,
  peopleTableDbid: null,
  tasksTableDbid: null,

  departmentNameFieldId: null,
  departmentLocationFieldId: null,
  personNameFieldId: null,

  taskNameFieldId: null,
  taskDueDateFieldId: null,
  taskStatusFieldId: null,

  departmentsPeopleRelationshipId: null,
  peopleTasksRelationshipId: null,
};

Examples of dependencies

departmentsTableDbid is needed before Department fields can be created.

departmentNameFieldId and departmentLocationFieldId are needed before those fields can be requested as lookups.

peopleTableDbid identifies People as the child in the first relationship and as the parent in the second.

Part 8

Quickbase Is the Source of Truth

JavaScript memory disappears when the page reloads. The finished Code Page therefore does not assume that its in-memorylessonStateis authoritative.

Schema reconstruction
PAGE LOAD
    ↓
Discover App DBID
    ↓
GET tables
    ↓
Find People / Departments / Tasks
    ↓
GET fields
    ↓
GET relationships
    ↓
Reconstruct lessonState
    ↓
Determine completed steps
    ↓
Enable the next valid action

If a student closes the browser after completing four steps and returns tomorrow, every JavaScript value begins asnullagain. The page re-reads Quickbase, discovers what actually exists, and reconstructs its progress.

Aha Moment

The authoritative system can rebuild transient client state

Whenever possible, application state should be reconstructed from the authoritative system rather than trusted solely to temporary browser memory. Quickbase itself tells this lesson what has already been built.

Part 9

Status-Aware Construction

The finished Code Page contains six schema-changing actions, but not every action is available at the same time.

1

Create Departments Table

2

Create Department Fields

3

Create Departments → People Relationship

4

Create Tasks Table

5

Create Task Fields

6

Create People → Tasks Relationship

A disabled button means either the action has already been completed or a prerequisite has not yet been satisfied.

Refresh Lesson Status

Refresh is deliberately separate from the six construction steps. It does not mutate the schema. It re-reads Quickbase, reconstructslessonState, recalculates progress, and determines which action is valid next.

Part 10

Step 1 — Create Departments

POST/v1/tables?appId={APP_DBID}

This is the first schema-changing request. The application DBID is discovered from the Quickbase Code Page context rather than hard-coded.

Request payload
{
  name: "Departments",
  description: "Departments used in Lesson 10",
  singleRecordName: "Department",
  pluralRecordName: "Departments"
}

The most consequential value returned is the new table'sid:

lessonState.departmentsTableDbid = data.id;

Do not reduce the response to a Boolean success flag. Quickbase returns metadata describing the table it just constructed, including properties such as its alias, key field, default sorting, nextFieldId, nextRecordId, storage information, and timestamps.

Part 11

Inspect What Quickbase Already Created

Immediately after Departments is created, Quickbase already has its system fields even though our code has not yet created Department Name or Location.

FieldOrigin
Date CreatedQuickbase automatic
Date ModifiedQuickbase automatic
Record ID#Quickbase automatic
Record OwnerQuickbase automatic
Last Modified ByQuickbase automatic
Department NameOur REST request
LocationOur REST request

Part 12

Step 2 — Create Department Fields

POST/v1/fields?tableId={TABLE_DBID}
Department Name
{
  label: "Department Name",
  fieldType: "text",
  appearsByDefault: true,
  addToForms: true
}
Location
{
  label: "Location",
  fieldType: "text",
  appearsByDefault: true,
  addToForms: true
}

The lesson intentionally creates the two fields with separate requests so each Quickbase response can be inspected independently and each assigned Field ID can be captured.

Part 13

Step 3 — Create Departments → People

The relationship now consumes identifiers produced by the preceding steps. Departments is the parent. People is the child.

POST/v1/tables/{PEOPLE_CHILD_DBID}/relationship
Relationship payload
{
  parentTableId: lessonState.departmentsTableDbid,

  foreignKeyField: {
    label: "Related Department"
  },

  lookupFieldIds: [
    lessonState.departmentNameFieldId,
    lessonState.departmentLocationFieldId
  ]
}

Watch what happens physically

We request a relationship, a reference-field label, and two parent fields to use as lookups. We do not separately create the relationship helper fields with the field endpoint.

Our request says

Parent = Departments

Child = People

Reference label = Related Department

Look up Department Name + Location

Quickbase builds

Relationship

Related Department reference field

Department Name lookup

Location lookup

Part 14

Why the Relationship Appears From the Child Side

During development, inspecting Departments returned no relationship, even though Departments clearly participated in Departments → People. Inspecting People exposed the relationship.

Departments
    │
    │ parent
    ▼
People
    │
    └── Related Department
        reference / foreign-key field

Quickbase's relationship endpoint is oriented around the child table containing the reference field. Therefore People exposes the Departments → People relationship.

This does not mean Departments is unrelated to People. It means the API representation is centered on the child-side field that physically stores the reference.

Aha Moment

Relationship metadata is child-oriented

The relationship's reference/foreign-key field resides on the child. That is why querying the child table's relationship endpoint exposes the relationship.

Part 15

Steps 4 and 5 — Create Tasks

After Departments → People is verified, the same construction pattern is reused to create Tasks.

POST/v1/tables?appId={APP_DBID}
Tasks table
{
  name: "Tasks",
  description: "Tasks used in Lesson 10",
  singleRecordName: "Task",
  pluralRecordName: "Tasks"
}
POST/v1/fields?tableId={TASKS_DBID}
FieldQuickbase field type
Task Nametext
Due Datedate
Statustext-multiple-choice
Status choices
properties: {
  choices: [
    "Not Started",
    "In Progress",
    "Complete"
  ],
  allowNewChoices: false
}

Part 16

Step 6 — Create People → Tasks

The second relationship reverses People's role. People was the child of Departments; now People becomes the parent of Tasks.

POST/v1/tables/{TASKS_CHILD_DBID}/relationship
People → Tasks payload
{
  parentTableId: lessonState.peopleTableDbid,

  foreignKeyField: {
    label: "Related Person"
  },

  lookupFieldIds: [
    lessonState.personNameFieldId
  ]
}

The Code Page discovers the People Name Field ID rather than assuming it is FID 6. Quickbase then creates the relationship support fields in Tasks.

Explicitly created earlier

Task Name

Due Date

Status

Relationship-derived schema

Related Person

People Name lookup

Part 17

JSON Is Part of the Teaching

The JSON output area in the Code Page is not merely debugging output. It deliberately separates what JavaScript requested, what Quickbase returned, and what identifiers JavaScript retained.

General operation output
{
  request: {
    method,
    endpoint,
    payload
  },

  quickbaseResponse: {
    ...
  },

  capturedLessonState: {
    ...
  }
}
Relationship operation output
{
  whatOurCodeExplicitlyRequested: {
    ...
  },

  whatQuickbaseCreatedForTheRelationship: {
    ...
  },

  quickbaseResponse: {
    ...
  },

  capturedLessonState: {
    ...
  }
}

Questions to ask while reading the output

  1. What did JavaScript explicitly ask Quickbase to create?
  2. What additional schema did Quickbase create automatically?
  3. What metadata did Quickbase return?
  4. Which identifiers did JavaScript capture for later requests?

Part 18

Final Schema Provenance

The completed schema contains fields from several different origins. Understanding that provenance is one of the central objectives of this lesson.

Departments

Quickbase system

Date Created

Date Modified

Record ID#

Record Owner

Last Modified By

Our API

Department Name

Location

People

Existing training fields

Name

Age

Favorite Color

Relationship-created

Related Department

Lookup fields

Department Name

Department Location

Tasks

Quickbase system

Date Created

Date Modified

Record ID#

Record Owner

Last Modified By

Our API

Task Name

Due Date

Status

Relationship-created

Related Person

Lookup

People Name — verify the exact label in Lesson 9

Part 19

When Is the Lesson Actually Complete?

The last POST returning HTTP 200 is not enough. The Code Page re-inspects Quickbase and declares the lesson complete only when the resulting schema can actually be discovered.

Completion Checklist

✓ People exists

✓ Departments exists

✓ Department fields exist

✓ Departments → People exists

✓ Tasks exists

✓ Task fields exist

✓ People → Tasks exists

Departments
     ↓
People
     ↓
Tasks

Part 20

Verify Everything With Lesson 9

Finish by returning to the Schema Explorer. Lesson 9 and Lesson 10 now form a closed loop: inspect, construct, then inspect again.

Departments

Verify its Table DBID, Department Name, Location, and standard system fields. Remember that the child-oriented relationship endpoint may show no relationship while inspecting Departments itself.

People

Verify Related Department, the Department lookup fields, and the Departments → People relationship. This is the child side of the first relationship.

Tasks

Verify Task Name, Due Date, Status, Related Person, the People lookup, and the People → Tasks relationship.

Lesson 10 Recap

What We Learned

API responses can become inputs to later API requests.
DBIDs and Field IDs should be discovered or captured, not guessed.
Field IDs are local to their tables.
Creating a table causes Quickbase to create system fields automatically.
Creating a relationship can create reference and lookup fields automatically.
Relationship metadata is child-oriented because the reference field resides on the child.
JavaScript state is temporary; Quickbase can reconstruct the application's real schema state.
Dynamic schema construction is a dependency chain, not a pile of unrelated POST requests.

During this lesson, our JavaScript explicitly created tables, ordinary fields, and relationships. Quickbase also created its own required system fields and relationship-derived fields.