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:
- Install and set up Harper locally
- Configure a Vite application to run inside Harper
- Define and deploy a GraphQL schema
- Create a custom Resource Class
- Connect our frontend to Harper’s REST endpoints
- 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:
- Open the
harper-todo-example/start/folder in your editor - Run:
npm install
npm run dev
- 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
descriptionfield
Deploy the Schema
Run:
harper deploy
In Harper Studio:
- Navigate to Databases
- Open the
TodoListtable
If no database exists, Harper automatically creates a default database named data.
Adding a Record (Testing)
In Harper Studio:
- Click + Add New Record(s)
- Replace the object with:
{
"status": "active",
"description": "finish todo app"
}
- 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:






