Skip to content

Commit bb5b5e0

Browse files
committed
Update first-harper-app page
1 parent 00c81f4 commit bb5b5e0

File tree

1 file changed

+66
-115
lines changed

1 file changed

+66
-115
lines changed
Lines changed: 66 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,97 @@
11
# Create Your First Application
2-
Now that you've set up Harper, let's build a simple Book API. Start by cloning the template:
2+
Now that you've set up Harper, let's build a simple API. Harper lets you build powerful APIs with minimal effort. In just a few minutes, you'll have a functional REST API with automatic validation, indexing, and querying—all without writing a single line of code.
3+
4+
## Setup Your Project
5+
Start by cloning the Harper application template:
36

47
```bash
58
git clone https://github.com/HarperDB/application-template my-book-app
69
cd my-book-app
710
```
811

9-
The template includes:
10-
- **schema.graphql** – Your GraphQL schema definition
11-
- **resources.js** – For custom application logic
12-
- **config.yaml** – Application-level settings
12+
## Create a Complete API with Just a Schema
13+
Harper's power comes from its schema-first approach. Edit your `schema.graphql` file to define a Book table:
1314

14-
## Define a GraphQL Schema
15-
Edit your `schema.graphql` file to create a Book table:
1615
```graphql
1716
type Book @table @export {
1817
id: ID @primaryKey
19-
title: String!
20-
author: String!
18+
title: String! @indexed
19+
author: String! @indexed
2120
publishedYear: Int
22-
genre: String
21+
genre: String @indexed
2322
}
2423
```
2524

26-
The schema above does several important things:
27-
- Creates a `Book` table with the `@table` directive
28-
- Makes the table accessible via REST and GraphQL using the `@export` directive
29-
- Defines an `id` field as the primary key with the `@primaryKey` directive
30-
- Requires `title` and `author` fields (marked with `!`)
31-
- Adds optional `publishedYear` and `genre` fields
25+
That's it! This simple schema gives you:
3226

33-
When you start your application, Harper will automatically create this table resource.
27+
- Automatic table creation with the `@table` directive
28+
- Full REST API with the `@export` directive (GET, POST, PUT, DELETE)
29+
- Data validation (title and author are required with `!`)
30+
- Fast querying with `@indexed` fields
31+
- Auto-generated primary keys with `@primaryKey`
3432

35-
## Extend the Resource Class
36-
Now let's create the business logic for our Book API by implementing a custom resource class. Update your `resources.js` file:
3733

38-
```js
39-
export class Books extends Resource {
40-
// Get a book by ID or list all books
41-
get() {
42-
const id = this.getId();
43-
44-
if (id) {
45-
// Return a single book
46-
return this.table.get(id);
47-
} else {
48-
// Return all books
49-
return this.table.get();
50-
}
51-
}
52-
53-
// Create a new book
54-
post(data) {
55-
// Validate required fields
56-
if (!data.title || !data.author) {
57-
return { error: "Title and author are required" };
58-
}
59-
60-
// Prevent primary key overriding
61-
if (data.id) delete data.id;
62-
63-
try {
64-
return this.table.post(data);
65-
} catch (error) {
66-
return { error: "Error creating book", details: error.message };
67-
}
68-
}
69-
}
34+
## Start Your Application
35+
```bash
36+
harperdb dev .
7037
```
71-
Let's break down what this JavaScript file is doing:
38+
Harper automatically creates your Book table and REST endpoints. You now have a complete API at `http://localhost:9926/Book/`
7239

73-
### Resource Class Extension
74-
```js
75-
export class Books extends Resource {
40+
## Test Your API
41+
### Create a book:
42+
```bash
43+
curl -X POST -H "Content-Type: application/json" \
44+
-d '{"title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "publishedYear": 1925, "genre": "Fiction"}' \
45+
http://localhost:9926/Book
7646
```
7747

78-
This line creates a custom `Books` class that extends Harper's built-in `Resource` class. By doing this, we inherit all the standard functionality while allowing us to customize behavior.
48+
### Get all books:
49+
```bash
50+
curl http://localhost:9926/Book
51+
```
7952

80-
### GET Method
81-
```js
82-
get() {
83-
const id = this.getId();
84-
85-
if (id) {
86-
return this.table.get(id);
87-
} else {
88-
return this.table.get();
89-
}
90-
}
53+
### Query by indexed fields:
54+
```bash
55+
curl "http://localhost:9926/Book?author=F. Scott Fitzgerald"
56+
curl "http://localhost:9926/Book?genre=Fiction"
57+
curl "http://localhost:9926/Book?publishedYear=1925&select(title,author)"
58+
```
59+
60+
### Get a specific book:
61+
```bash
62+
curl http://localhost:9926/Book/BOOK_ID_HERE
9163
```
9264

93-
The `get()` method handles HTTP GET requests to our Book endpoint. It:
94-
- Logs that a request was received (helpful for debugging)
95-
- Checks if an ID was provided in the URL path
96-
- If an ID exists, returns a single book by that ID
97-
- If no ID exists, checks for a `genre` query parameter
98-
- Returns all books, filtered by genre if specified
65+
## What You Get Automatically
66+
Harper provides enterprise-grade features out of the box:
67+
68+
- **Content negotiation** (JSON, CBOR, MessagePack, CSV)
69+
- **Authentication** (Basic, JWT, Cookie)
70+
- **Caching headers** and ETags
71+
- **Data validation** based on your schema
72+
- **Automatic indexing** for fast queries
73+
- **Error handling** and proper HTTP status codes
74+
75+
## Add Custom Logic (Optional)
76+
Only when you need custom business logic should you add code. Create a `resources.js` file to extend the default behavior:
9977

100-
### POST Method
10178
```js
102-
post(data) {
103-
// Validate required fields
104-
if (!data.title || !data.author) {
105-
return { error: "Title and author are required" };
79+
export class Books extends Resource {
80+
// Add custom validation or computed fields
81+
post(data) {
82+
if (!data.title || !data.author) {
83+
return { error: "Title and author are required" };
84+
}
85+
86+
// Add publication decade for analytics
87+
if (data.publishedYear) {
88+
data.decade = Math.floor(data.publishedYear / 10) * 10;
89+
}
90+
91+
return this.table.post(data);
10692
}
107-
108-
// Prevent primary key overriding
109-
if (data.id) delete data.id;
110-
111-
return this.table.post(data);
11293
}
11394
```
11495

115-
The `post()` method handles HTTP POST requests to create new books. It:
116-
- Handles both string and object data formats
117-
- Validates that required fields (`title` and `author`) are present
118-
- Removes any provided `id` field to prevent primary key conflicts
119-
- Creates the book record in the database
120-
- Returns the result or an error message if something goes wrong
121-
122-
## Run and Test
123-
1. Start your application:
124-
```bash
125-
harperdb dev .
126-
```
127-
2. Create a book:
128-
```bash\
129-
curl -X POST -H "Content-Type: application/json" \ -d '{"title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "publishedYear": 1925, "genre": "Fiction"}' \ http://localhost:9926/Books
130-
```
131-
3. Retrieve a book by ID:
132-
```bash
133-
curl http://localhost:9926/Book/BOOK_ID_HERE
134-
```
135-
4. Get all books in a genre:
136-
```bash
137-
curl http://localhost:9926/Book?genre=Fiction
138-
```
139-
140-
This simple Book API demonstrates Harper's key features:
141-
- Schema-based table definitions with GraphQL
142-
- Custom resource extensions for business logic
143-
- Automatic REST endpoint generation
144-
- Built-in data validation and error handling
145-
146-
You can build on this foundation by adding more fields, implementing additional methods, or creating relationships to other tables.
96+
## Key Takeaway
97+
Harper's schema-driven approach means you can build production-ready APIs in minutes, not hours. Start with pure schema definitions to get 90% of your functionality, then add custom code only where needed. This gives you the best of both worlds: rapid development with the flexibility to customize when required.

0 commit comments

Comments
 (0)