Click Below to Get the Code

Browse, clone, and build from real-world templates powered by Harper.
Blog
GitHub Logo

Getting Started with Harper’s Resource API

Learn how to build a full-stack Todo app using Harper’s Resource API, including schema-first data modeling, automatic REST API generation, custom backend logic, and seamless frontend integration for high-performance application development.
Blog

Getting Started with Harper’s Resource API

By
Austin Akers
March 4, 2026
By
Austin Akers
March 4, 2026
By
Austin Akers
March 4, 2026
March 4, 2026
Learn how to build a full-stack Todo app using Harper’s Resource API, including schema-first data modeling, automatic REST API generation, custom backend logic, and seamless frontend integration for high-performance application development.
Austin Akers
Head of Developer Relations

Getting Started with Harper’s Resource API

Harper simplifies full-stack development by combining data modeling, API generation, and runtime execution into a single platform.

In this tutorial, we’ll build a simple Todo application while exploring how Harper’s Resource API allows you to model data and extend REST endpoints with custom logic.

By the end of this guide, you’ll understand how to:

  • Install and configure Harper locally
  • Run a Vite application inside Harper
  • Define a schema using a schema-first approach
  • Deploy a table
  • Extend that table using a custom Resource Class
  • Connect your frontend to Resource-backed REST endpoints

Overview

In this article, we will:

  1. Install and set up Harper locally
  2. Configure a Vite application to run inside Harper
  3. Define and deploy a GraphQL schema
  4. Create a custom Resource Class
  5. Connect our frontend to Harper’s REST endpoints
  6. Add backend validation logic

Install and Set Up Harper

Harper is installed via the harperdb CLI package.

Open your terminal and run:

npm install -g harperdb

Once installation completes, start Harper:

harper

The first time you run harper, you’ll be prompted to configure:

  • Destination – Where Harper will be installed on your machine
  • Username – Used to log into Harper Studio
  • Password – Used to log into Harper Studio
  • Configuration options

After completing setup, Harper will start locally.

Access Harper Studio

While Harper is running, navigate to:

http://localhost:9925/

Log in using the credentials you created during setup.

In Harper Studio, you’ll see:

  • Applications – Manage applications
  • Databases – Manage databases, tables, and records
  • APIs – View and test generated REST endpoints
  • Status – Monitor system metrics
  • Logs – View instance logs
  • Config – Manage roles and users

Application Setup

Before integrating Harper, clone the Todo example app:

git clone https://github.com/HarperFast/harper-todo-example

Then:

  1. Open the harper-todo-example/start/ folder in your editor
  2. Run:

npm install
npm run dev

  1. Navigate to:

http://localhost:5173/

The application runs — but:

  • It is not running inside Harper
  • It does not yet use Harper for CRUD operations

Let’s fix that.

Configuring the Application to Run Inside Harper

1. Install the Harper Vite Plugin

npm install -D @harperfast/vite-plugin

2. Update config.yaml

Add the plugin:

'@harperfast/vite-plugin':
 package: '@harperfast/vite-plugin'

3. Update package.json

Replace the dev script with:

"dev": "harper run ."

Restart the app:

npm run dev

Now navigate to:

http://localhost:9926/

Your application is now running inside Harper.

What Did We Just Do?

By running inside Harper, your application now benefits from:

  • Integrated database access
  • Automatic REST API generation
  • In-memory caching
  • Low-latency backend execution

Defining Our Table (Schema-First)

Harper uses a schema-first approach with GraphQL.

Open schema.graphql and add:

type TodoList @table {
 id: ID @primaryKey
 status: String @index
 description: String
}

This defines:

  • A table named TodoList
  • A primary key id
  • Indexed status
  • A description field

Deploy the Schema

Run:

harper deploy

In Harper Studio:

  • Navigate to Databases
  • Open the TodoList table

If no database exists, Harper automatically creates a default database named data.

Adding a Record (Testing)

In Harper Studio:

  1. Click + Add New Record(s)
  2. Replace the object with:

{
 "status": "active",
 "description": "finish todo app"
}

  1. Click Save Changes

Your first record is now stored.

Understanding Auto-Generated REST Endpoints

When you define a table, Harper automatically generates REST endpoints for it.

You can view and test them in:

Harper Studio → APIs

These endpoints allow standard CRUD operations.

However, what if we want to:

  • Validate input
  • Modify data before saving
  • Add business logic

That’s where the Resource Class comes in.

What Is the Resource Class?

The Resource Class extends a table and allows you to:

  • Intercept REST operations
  • Modify or validate data
  • Add custom logic
  • Restrict scope to a specific table

Instead of using the base Resource class (which can access all tables), we extend a specific table for better scope control.

Creating Our First Resource Class

Open resources.js.

By default, it looks like:

import { tables } from 'harperdb';

export class MyCustomResource extends tables.TableName {
 static loadAsInstance = false;
}

Update for TodoList

First, reference the table:

import { tables } from 'harperdb';

const TodoListTable = tables.TodoList;

Now create the Resource:

export class TodoListResource extends TodoListTable {
 static loadAsInstance = false;
}

This automatically creates a REST endpoint at:

/TodoListResource/

Fetching Todos

Open src/main.ts and locate fetchTodos():

todos = await fetch(`/TodoListResource/`)
 .then(res => res.json());

This fetches all records from the TodoList table via our Resource endpoint.

Updating Todo Status

To update a record, we use a PUT request:

await fetch(`/TodoListResource/${id}`, {
 method: 'PUT',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: todos.find(todo => todo.id === id)?.description,
   status: todos.find(todo => todo.id === id)?.status === "active"
     ? "completed"
     : "active",
 }),
});

Updating Todo Description

await fetch(`/TodoListResource/${id}`, {
 method: 'PUT',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: newText,
   status: todos.find(todo => todo.id === id)?.status,
 }),
});

Adding Backend Validation with the Resource Class

Now let’s trim the description before saving it.

Update resources.js:

export class TodoListResource extends TodoListTable {
 static loadAsInstance = false;

 put(target, taskItemData) {
   return super.put(target, {
     id: taskItemData.id,
     description: taskItemData.description.trim(),
     status: taskItemData.status
   });
 }

 post(target, taskItemData) {
   return super.post(target, {
     description: taskItemData.description.trim(),
     status: taskItemData.status
   });
 }
}

Now:

  • Descriptions are trimmed automatically
  • Validation logic lives on the backend
  • Frontend remains clean

Adding a New Todo

await fetch(`/TodoListResource/`, {
 method: 'POST',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: todoText,
   status: "active",
 }),
});

We do not provide an id — Harper automatically generates one.

Deleting a Todo

await fetch(`/TodoListResource/${id}`, {
 method: 'DELETE',
});

Conclusion

In this tutorial, we built a full-stack Todo application using Harper’s Resource API.

We demonstrated how to:

  • Run a frontend application inside Harper
  • Define a schema using a schema-first approach
  • Automatically generate REST endpoints
  • Extend those endpoints using a custom Resource Class
  • Add backend validation logic
  • Perform full CRUD operations

Harper enables a streamlined development experience by combining:

  • Data modeling
  • API generation
  • Runtime execution
  • Backend extensibility

—all within a single platform.

To explore more, visit:

https://www.harper.fast/

Getting Started with Harper’s Resource API

Harper simplifies full-stack development by combining data modeling, API generation, and runtime execution into a single platform.

In this tutorial, we’ll build a simple Todo application while exploring how Harper’s Resource API allows you to model data and extend REST endpoints with custom logic.

By the end of this guide, you’ll understand how to:

  • Install and configure Harper locally
  • Run a Vite application inside Harper
  • Define a schema using a schema-first approach
  • Deploy a table
  • Extend that table using a custom Resource Class
  • Connect your frontend to Resource-backed REST endpoints

Overview

In this article, we will:

  1. Install and set up Harper locally
  2. Configure a Vite application to run inside Harper
  3. Define and deploy a GraphQL schema
  4. Create a custom Resource Class
  5. Connect our frontend to Harper’s REST endpoints
  6. Add backend validation logic

Install and Set Up Harper

Harper is installed via the harperdb CLI package.

Open your terminal and run:

npm install -g harperdb

Once installation completes, start Harper:

harper

The first time you run harper, you’ll be prompted to configure:

  • Destination – Where Harper will be installed on your machine
  • Username – Used to log into Harper Studio
  • Password – Used to log into Harper Studio
  • Configuration options

After completing setup, Harper will start locally.

Access Harper Studio

While Harper is running, navigate to:

http://localhost:9925/

Log in using the credentials you created during setup.

In Harper Studio, you’ll see:

  • Applications – Manage applications
  • Databases – Manage databases, tables, and records
  • APIs – View and test generated REST endpoints
  • Status – Monitor system metrics
  • Logs – View instance logs
  • Config – Manage roles and users

Application Setup

Before integrating Harper, clone the Todo example app:

git clone https://github.com/HarperFast/harper-todo-example

Then:

  1. Open the harper-todo-example/start/ folder in your editor
  2. Run:

npm install
npm run dev

  1. Navigate to:

http://localhost:5173/

The application runs — but:

  • It is not running inside Harper
  • It does not yet use Harper for CRUD operations

Let’s fix that.

Configuring the Application to Run Inside Harper

1. Install the Harper Vite Plugin

npm install -D @harperfast/vite-plugin

2. Update config.yaml

Add the plugin:

'@harperfast/vite-plugin':
 package: '@harperfast/vite-plugin'

3. Update package.json

Replace the dev script with:

"dev": "harper run ."

Restart the app:

npm run dev

Now navigate to:

http://localhost:9926/

Your application is now running inside Harper.

What Did We Just Do?

By running inside Harper, your application now benefits from:

  • Integrated database access
  • Automatic REST API generation
  • In-memory caching
  • Low-latency backend execution

Defining Our Table (Schema-First)

Harper uses a schema-first approach with GraphQL.

Open schema.graphql and add:

type TodoList @table {
 id: ID @primaryKey
 status: String @index
 description: String
}

This defines:

  • A table named TodoList
  • A primary key id
  • Indexed status
  • A description field

Deploy the Schema

Run:

harper deploy

In Harper Studio:

  • Navigate to Databases
  • Open the TodoList table

If no database exists, Harper automatically creates a default database named data.

Adding a Record (Testing)

In Harper Studio:

  1. Click + Add New Record(s)
  2. Replace the object with:

{
 "status": "active",
 "description": "finish todo app"
}

  1. Click Save Changes

Your first record is now stored.

Understanding Auto-Generated REST Endpoints

When you define a table, Harper automatically generates REST endpoints for it.

You can view and test them in:

Harper Studio → APIs

These endpoints allow standard CRUD operations.

However, what if we want to:

  • Validate input
  • Modify data before saving
  • Add business logic

That’s where the Resource Class comes in.

What Is the Resource Class?

The Resource Class extends a table and allows you to:

  • Intercept REST operations
  • Modify or validate data
  • Add custom logic
  • Restrict scope to a specific table

Instead of using the base Resource class (which can access all tables), we extend a specific table for better scope control.

Creating Our First Resource Class

Open resources.js.

By default, it looks like:

import { tables } from 'harperdb';

export class MyCustomResource extends tables.TableName {
 static loadAsInstance = false;
}

Update for TodoList

First, reference the table:

import { tables } from 'harperdb';

const TodoListTable = tables.TodoList;

Now create the Resource:

export class TodoListResource extends TodoListTable {
 static loadAsInstance = false;
}

This automatically creates a REST endpoint at:

/TodoListResource/

Fetching Todos

Open src/main.ts and locate fetchTodos():

todos = await fetch(`/TodoListResource/`)
 .then(res => res.json());

This fetches all records from the TodoList table via our Resource endpoint.

Updating Todo Status

To update a record, we use a PUT request:

await fetch(`/TodoListResource/${id}`, {
 method: 'PUT',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: todos.find(todo => todo.id === id)?.description,
   status: todos.find(todo => todo.id === id)?.status === "active"
     ? "completed"
     : "active",
 }),
});

Updating Todo Description

await fetch(`/TodoListResource/${id}`, {
 method: 'PUT',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: newText,
   status: todos.find(todo => todo.id === id)?.status,
 }),
});

Adding Backend Validation with the Resource Class

Now let’s trim the description before saving it.

Update resources.js:

export class TodoListResource extends TodoListTable {
 static loadAsInstance = false;

 put(target, taskItemData) {
   return super.put(target, {
     id: taskItemData.id,
     description: taskItemData.description.trim(),
     status: taskItemData.status
   });
 }

 post(target, taskItemData) {
   return super.post(target, {
     description: taskItemData.description.trim(),
     status: taskItemData.status
   });
 }
}

Now:

  • Descriptions are trimmed automatically
  • Validation logic lives on the backend
  • Frontend remains clean

Adding a New Todo

await fetch(`/TodoListResource/`, {
 method: 'POST',
 headers: {
   'Content-Type': 'application/json',
 },
 body: JSON.stringify({
   description: todoText,
   status: "active",
 }),
});

We do not provide an id — Harper automatically generates one.

Deleting a Todo

await fetch(`/TodoListResource/${id}`, {
 method: 'DELETE',
});

Conclusion

In this tutorial, we built a full-stack Todo application using Harper’s Resource API.

We demonstrated how to:

  • Run a frontend application inside Harper
  • Define a schema using a schema-first approach
  • Automatically generate REST endpoints
  • Extend those endpoints using a custom Resource Class
  • Add backend validation logic
  • Perform full CRUD operations

Harper enables a streamlined development experience by combining:

  • Data modeling
  • API generation
  • Runtime execution
  • Backend extensibility

—all within a single platform.

To explore more, visit:

https://www.harper.fast/

Learn how to build a full-stack Todo app using Harper’s Resource API, including schema-first data modeling, automatic REST API generation, custom backend logic, and seamless frontend integration for high-performance application development.

Download

White arrow pointing right
Learn how to build a full-stack Todo app using Harper’s Resource API, including schema-first data modeling, automatic REST API generation, custom backend logic, and seamless frontend integration for high-performance application development.

Download

White arrow pointing right
Learn how to build a full-stack Todo app using Harper’s Resource API, including schema-first data modeling, automatic REST API generation, custom backend logic, and seamless frontend integration for high-performance application development.

Download

White arrow pointing right

Explore Recent Resources

Podcast
GitHub Logo

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Select*
Podcast
Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Person with short hair wearing a light blue patterned shirt, smiling widely outdoors with blurred greenery and trees in the background.
Austin Akers
Head of Developer Relations
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers
Mar 2026
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers
Case Study
GitHub Logo

How a $1B+ Retailer Unlocked $92M in Annual Revenue, Without Touching the Origin.

When experimentation logic, redirect limits, and origin failures were quietly costing a $1B+ retailer tens of millions, Harper delivered edge-deployed acceleration without re-platforming. 47x ROI. Six weeks to prove it.
Case Study
When experimentation logic, redirect limits, and origin failures were quietly costing a $1B+ retailer tens of millions, Harper delivered edge-deployed acceleration without re-platforming. 47x ROI. Six weeks to prove it.
Person with short dark hair and moustache, wearing a colorful plaid shirt, smiling outdoors in a forested mountain landscape.
Aleks Haugom
Senior Manager of GTM & Marketing
Case Study

How a $1B+ Retailer Unlocked $92M in Annual Revenue, Without Touching the Origin.

When experimentation logic, redirect limits, and origin failures were quietly costing a $1B+ retailer tens of millions, Harper delivered edge-deployed acceleration without re-platforming. 47x ROI. Six weeks to prove it.
Aleks Haugom
Mar 2026
Case Study

How a $1B+ Retailer Unlocked $92M in Annual Revenue, Without Touching the Origin.

When experimentation logic, redirect limits, and origin failures were quietly costing a $1B+ retailer tens of millions, Harper delivered edge-deployed acceleration without re-platforming. 47x ROI. Six weeks to prove it.
Aleks Haugom
Case Study

How a $1B+ Retailer Unlocked $92M in Annual Revenue, Without Touching the Origin.

When experimentation logic, redirect limits, and origin failures were quietly costing a $1B+ retailer tens of millions, Harper delivered edge-deployed acceleration without re-platforming. 47x ROI. Six weeks to prove it.
Aleks Haugom