Skip to content

Commit 061fbf0

Browse files
committed
Address ALL PR comments
1 parent 72a533e commit 061fbf0

File tree

3 files changed

+128
-286
lines changed

3 files changed

+128
-286
lines changed

docs/developers/applications/README.md

Lines changed: 1 addition & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -28,219 +28,9 @@ flowchart LR
2828
end
2929
```
3030

31-
## Getting up and Running
32-
33-
### Pre-Requisites
34-
35-
We assume you are running Harper version 4.2 or greater, which supports Harper Application architecture (in previous versions, this is 'custom functions').
36-
37-
### Scaffolding our Application Directory
38-
39-
Let's create and initialize a new directory for our application. It is recommended that you start by using the [Harper application template](https://github.com/HarperDB/application-template). Assuming you have `git` installed, you can create your project directory by cloning:
40-
41-
```shell
42-
> git clone https://github.com/HarperDB/application-template my-app
43-
> cd my-app
44-
```
45-
46-
<details>
47-
48-
<summary>You can also start with an empty application directory if you'd prefer.</summary>
49-
50-
To create your own application from scratch, you'll may want to initialize it as an npm package with the \`type\` field set to \`module\` in the \`package.json\` so that you can use the EcmaScript module syntax used in this tutorial:
51-
52-
```shell
53-
> mkdir my-app
54-
> cd my-app
55-
> npm init -y esnext
56-
```
57-
58-
</details>
59-
60-
<details>
61-
62-
<summary>If you want to version control your application code, you can adjust the remote URL to your repository.</summary>
63-
64-
Here's an example for a github repo:
65-
66-
```shell
67-
> git remote set-url origin [email protected]:/<github-user>/<github-repo>
68-
```
69-
70-
Locally developing your application and then committing your app to a source control is a great way to manage your code and configuration, and then you can [directly deploy from your repository](./#deploying-your-application).
71-
72-
</details>
73-
74-
## Creating our first Table
75-
76-
The core of a Harper application is the database, so let's create a database table!
77-
78-
A quick and expressive way to define a table is through a [GraphQL Schema](https://graphql.org/learn/schema). Using your editor of choice, edit the file named `schema.graphql` in the root of the application directory, `my-app`, that we created above. To create a table, we will need to add a `type` of `@table` named `Dog` (and you can remove the example table in the template):
79-
80-
```graphql
81-
type Dog @table {
82-
# properties will go here soon
83-
}
84-
```
85-
86-
And then we'll add a primary key named `id` of type `ID`:
87-
88-
_(Note: A GraphQL schema is a fast method to define tables in Harper, but you are by no means required to use GraphQL to query your application, nor should you necessarily do so)_
89-
90-
```graphql
91-
type Dog @table {
92-
id: ID @primaryKey
93-
}
94-
```
95-
96-
Now we tell Harper to run this as an application:
97-
98-
```shell
99-
> harperdb dev . # tell Harper cli to run current directory as an application in dev mode
100-
```
101-
102-
Harper will now create the `Dog` table and its `id` attribute we just defined. Not only is this an easy way to create a table, but this schema is included in our application, which will ensure that this table exists wherever we deploy this application (to any Harper instance).
103-
104-
## Adding Attributes to our Table
105-
106-
Next, let's expand our `Dog` table by adding additional typed attributes for dog `name`, `breed` and `age`.
107-
108-
```graphql
109-
type Dog @table {
110-
id: ID @primaryKey
111-
name: String
112-
breed: String
113-
age: Int
114-
}
115-
```
116-
117-
This will ensure that new records must have these properties with these types.
118-
119-
Because we ran `harperdb dev .` earlier (dev mode), Harper is now monitoring the contents of our application directory for changes and reloading when they occur. This means that once we save our schema file with these new attributes, Harper will automatically reload our application, read `my-app/schema.graphql` and update the `Dog` table and attributes we just defined. The dev mode will also ensure that any logging or errors are immediately displayed in the console (rather only in the log file).
120-
121-
As a document database, Harper supports heterogeneous records, so you can freely specify additional properties on any record. If you do want to restrict the records to only defined properties, you can always do that by adding the `sealed` directive:
122-
123-
```graphql
124-
type Dog @table @sealed {
125-
id: ID @primaryKey
126-
name: String
127-
breed: String
128-
age: Int
129-
tricks: [String]
130-
}
131-
```
132-
133-
If you are using Harper Studio, we can now [add JSON-formatted records](../../administration/harper-studio/manage-databases-browse-data.md#add-a-record) to this new table in the studio or upload data as [CSV from a local file or URL](../../administration/harper-studio/manage-databases-browse-data.md#load-csv-data). A third, more advanced, way to add data to your database is to use the [operations API](../operations-api/), which provides full administrative control over your new Harper instance and tables.
134-
135-
## Adding an Endpoint
136-
137-
Now that we have a running application with a database (with data if you imported any data), let's make this data accessible from a RESTful URL by adding an endpoint. To do this, we simply add the `@export` directive to our `Dog` table:
138-
139-
```graphql
140-
type Dog @table @export {
141-
id: ID @primaryKey
142-
name: String
143-
breed: String
144-
age: Int
145-
tricks: [String]
146-
}
147-
```
148-
149-
By default the application HTTP server port is `9926` (this can be [configured here](../../deployments/configuration.md#http)), so the local URL would be [http://localhost:9926/Dog/](http://localhost:9926/Dog/) with a full REST API. We can PUT or POST data into this table using this new path, and then GET or DELETE from it as well (you can even view data directly from the browser). If you have not added any records yet, we could use a PUT or POST to add a record. PUT is appropriate if you know the id, and POST can be used to assign an id:
150-
151-
```http
152-
POST /Dog/
153-
Content-Type: application/json
154-
155-
{
156-
"name": "Harper",
157-
"breed": "Labrador",
158-
"age": 3,
159-
"tricks": ["sits"]
160-
}
161-
```
162-
163-
With this a record will be created and the auto-assigned id will be available through the `Location` header. If you added a record, you can visit the path `/Dog/<id>` to view that record. Alternately, the curl command `curl http://localhost:9926/Dog/<id>` will achieve the same thing.
164-
165-
## Authenticating Endpoints
166-
167-
These endpoints automatically support `Basic`, `Cookie`, and `JWT` authentication methods. See the documentation on [security](../security/) for more information on different levels of access.
168-
169-
By default, Harper also automatically authorizes all requests from loopback IP addresses (from the same computer) as the superuser, to make it simple to interact for local development. If you want to test authentication/authorization, or enforce stricter security, you may want to disable the [`authentication.authorizeLocal` setting](../../deployments/configuration.md#authentication).
170-
171-
### Content Negotiation
172-
173-
These endpoints support various content types, including `JSON`, `CBOR`, `MessagePack` and `CSV`. Simply include an `Accept` header in your requests with the preferred content type. We recommend `CBOR` as a compact, efficient encoding with rich data types, but `JSON` is familiar and great for web application development, and `CSV` can be useful for exporting data to spreadsheets or other processing.
174-
175-
Harper works with other important standard HTTP headers as well, and these endpoints are even capable of caching interaction:
176-
177-
```
178-
Authorization: Basic <base64 encoded user:pass>
179-
Accept: application/cbor
180-
If-None-Match: "etag-id" # browsers can automatically provide this
181-
```
182-
183-
## Querying
184-
185-
Querying your application database is straightforward and easy, as tables exported with the `@export` directive are automatically exposed via [REST endpoints](../rest.md). Simple queries can be crafted through [URL query parameters](https://en.wikipedia.org/wiki/Query_string).
186-
187-
In order to maintain reasonable query speed on a database as it grows in size, it is critical to select and establish the proper indexes. So, before we add the `@export` declaration to our `Dog` table and begin querying it, let's take a moment to target some table properties for indexing. We'll use `name` and `breed` as indexed table properties on our `Dog` table. All we need to do to accomplish this is tag these properties with the `@indexed` directive:
188-
189-
```graphql
190-
type Dog @table {
191-
id: ID @primaryKey
192-
name: String @indexed
193-
breed: String @indexed
194-
owner: String
195-
age: Int
196-
tricks: [String]
197-
}
198-
```
199-
200-
And finally, we'll add the `@export` directive to expose the table as a RESTful endpoint
201-
202-
```graphql
203-
type Dog @table @export {
204-
id: ID @primaryKey
205-
name: String @indexed
206-
breed: String @indexed
207-
owner: String
208-
age: Int
209-
tricks: [String]
210-
}
211-
```
212-
213-
Now we can start querying. Again, we just simply access the endpoint with query parameters (basic GET requests), like:
214-
215-
```
216-
http://localhost:9926/Dog/?name=Harper
217-
http://localhost:9926/Dog/?breed=Labrador
218-
http://localhost:9926/Dog/?breed=Husky&name=Balto&select(id,name,breed)
219-
```
220-
221-
Congratulations, you now have created a secure database application backend with a table, a well-defined structure, access controls, and a functional REST endpoint with query capabilities! See the [REST documentation for more information on HTTP access](../rest.md) and see the [Schema reference](defining-schemas.md) for more options for defining schemas.
222-
223-
> Additionally, you may now use GraphQL (over HTTP) to create queries. See the documentation for that new feature [here](../../technical-details/reference/graphql.md).
224-
225-
## Deploying your Application
226-
227-
This guide assumes that you're building a Harper application locally. If you have a cloud instance available, you can deploy it by doing the following:
228-
229-
* Commit and push your application component directory code (i.e., the `my-app` directory) to a Github repo. In this tutorial we started with a clone of the application-template. To commit and push to your own repository, change the origin to your repo: `git remote set-url origin [email protected]:your-account/your-repo.git`
230-
* Go to the applications section of your target cloud instance in the [Harper Studio](../../administration/harper-studio/manage-applications.md).
231-
* In the left-hand menu of the applications IDE, click 'deploy' and specify a package location reference that follows the [npm package specification](https://docs.npmjs.com/cli/v8/using-npm/package-spec) (i.e., a string like `HarperDB/Application-Template` or a URL like `https://github.com/HarperDB/application-template`, for example, that npm knows how to install).
232-
233-
You can also deploy your application from your repository by directly using the [`deploy_component` operation](../operations-api/components.md#deploy-component).
234-
235-
Once you have deployed your application to a Harper cloud instance, you can start scaling your application by adding additional instances in other regions.
236-
237-
With the help of a global traffic manager/load balancer configured, you can distribute incoming requests to the appropriate server. You can deploy and re-deploy your application to all the nodes in your mesh.
238-
239-
Now, with an application that you can deploy, update, and re-deploy, you have an application that is horizontally and globally scalable!
240-
24131
## Custom Functionality with JavaScript
24232

243-
So far we have built an application entirely through schema configuration. However, if your application requires more custom functionality, you will probably want to employ your own JavaScript modules to implement more specific features and interactions. This gives you tremendous flexibility and control over how data is accessed and modified in Harper. Let's take a look at how we can use JavaScript to extend and define "resources" for custom functionality. Let's add a property to the dog records when they are returned, that includes their age in human years. In Harper, data is accessed through our [Resource API](../../technical-details/reference/resource.md), a standard interface to access data sources, tables, and make them available to endpoints. Database tables are `Resource` classes, and so extending the function of a table is as simple as extending their class.
33+
[The getting started guide](../../getting-started/install-harper.md) covers how to build an application entirely through schema configuration. However, if your application requires more custom functionality, you will probably want to employ your own JavaScript modules to implement more specific features and interactions. This gives you tremendous flexibility and control over how data is accessed and modified in Harper. Let's take a look at how we can use JavaScript to extend and define "resources" for custom functionality. Let's add a property to the dog records when they are returned, that includes their age in human years. In Harper, data is accessed through our [Resource API](../../technical-details/reference/resource.md), a standard interface to access data sources, tables, and make them available to endpoints. Database tables are `Resource` classes, and so extending the function of a table is as simple as extending their class.
24434

24535
To define custom (JavaScript) resources as endpoints, we need to create a `resources.js` module (this goes in the root of your application folder). And then endpoints can be defined with Resource classes that `export`ed. This can be done in addition to, or in lieu of the `@export`ed types in the schema.graphql. If you are exporting and extending a table you defined in the schema make sure you remove the `@export` from the schema so that don't export the original table or resource to the same endpoint/path you are exporting with a class. Resource classes have methods that correspond to standard HTTP/REST methods, like `get`, `post`, `patch`, and `put` to implement specific handling for any of these methods (for tables they all have default implementations). To do this, we get the `Dog` class from the defined tables, extend it, and export it:
24636

0 commit comments

Comments
 (0)