HarperDB のカスタム関数(Custom Functions)を使用して、REST APIを構築する


HarperDBは組織全体でのデータの収集、配布、分析のための分散型データベースソリューションです。HarperDBは考えられるほぼすべてのユースケースに対して、比類のない柔軟性、セキュリティ、価値を提供し、クラウド、オンプレミス、エッジで実行できる単一のインストールでそれらすべてを実現します。

HarperDBのカスタム関数（Custom Functions）はHarperDBデータベース内で独自に作成されたユーザー定義の関数です。カスタム関数を作成することにより、ユーザーは特定のビジネスロジックや処理をカプセル化し、再利用可能な関数としてデータベース内に定義することができます。

この記事でHarperDBのカスタム関数でREST APIを構築する手順を記載します。

## データベースのを作成

まずHarperDBのアカウントを作成し、アカウントのための組織を作成する必要があります

https://studio.harperdb.io/sign-up

作成したら、ダッシュボードが表示されます。ダッシュボードから新しい HarperDB クラウドインスタンスを起動できます。

![ダッシュボード](https://res.cloudinary.com/dsoombpif/image/upload/v1685112008/1_Instances_qtl6vc.png)

“Create New HarperDB Cloud Instance” をクリックすると、インスタンスタイプを選択するダイアログが表示されます。ローカルにインストールされたインスタンスまたはAWSまたはVerizon Wavelengthのインスタンスのいずれかを選択できます。私の場合、AWSを選択し、他のオプションはデフォルト値のままにしておきました。

![インスタンス詳細](https://res.cloudinary.com/dsoombpif/image/upload/v1685112008/2_Instance_Detail_onmrc9.png)

HarperDBの素晴らしい点は、サービスを評価するために無料でシングルインスタンスを作成できることです。“Add Instance”をクリックしたら、インスタンスを作成されて、ダッシュボードにスピンアップされます。

![インスタンス一覧](https://res.cloudinary.com/dsoombpif/image/upload/v1685112008/3_Instance_List_uqv9ow.png)

## スキーマとテーブルを作成

私たちのスキーマは基本的に、操作できるさまざまなテーブルを保存できる場所です。
"dev"というスキーマ、その中に"dog"というテーブルを作成します。
dogテーブルのハッシュ属性に"id"を入力します。

![スキーマ](https://res.cloudinary.com/dsoombpif/image/upload/v1685112008/4_Schema_ly3eaa.png)

作成されたテーブルは以下の列があります。
- id
- \_\_createdtime__
- \_\_updatedtime__

右上の「＋」アイコンをクリックして、以下のデータを入力して、保存アイコンをクリックしたら、3つのレコードを挿入されます。
```json
[
    {
        "id": 1,
        "dog_name": "Penny",
        "owner_name": "Kyle",
        "breed_id": 154,
        "age": 7,
        "weight_lbs": 38
    },
    {
        "id": 2,
        "dog_name": "Harper",
        "owner_name": "Stephen",
        "breed_id": 346,
        "age": 7,
        "weight_lbs": 55,
        "adorable": true
    },
    {
        "id": 3,
        "dog_name": "Alby",
        "owner_name": "Kaylan",
        "breed_id": 348,
        "age": 7,
        "weight_lbs": 84,
        "adorable": true
    }
]
```

挿入したレコードが表示されます。

![レコード一覧](https://res.cloudinary.com/dsoombpif/image/upload/v1685112008/5_Records_y6nvm2.png)

## カスタム関数(Custom Functions)でREST APIを作成

右上のメニューに"functions"をクリックしたら、カスタム関数画面に遷移します。
「/dog/routes」セクションの下に、API エンドポイントを含む example.js ファイルが表示されます。

![レコード一覧](https://res.cloudinary.com/dsoombpif/image/upload/v1685112009/6_Default_REST_gnllkz.png)

デフォルトで以下のエンドポイントを作成されました。
* 一覧取得エンドポイント: GET /
* 登録エンドポイント: POST /
* 詳細取得エンドポイント: GET /{id}

独自の REST API エンドポイントを作成しましょう。

## 一覧取得エンドポイント

デフォルトの「GET /」APIをベースに、preValidation（認証）を追加したら、全てのレコードの一覧を取得するAPIをできます。

```
server.route({
  url: '/',
  method: 'GET',
  preValidation: (request) => customValidation(request, logger),
  handler: (request) => {
    request.body= {
      operation: 'sql',
      sql: 'SELECT * FROM dev.dog ORDER BY dog_name'
    };
    return hdbCore.requestWithoutAuthentication(request);
  }
});
```

## 詳細取得エンドポイント

デフォルトの「GET /{id}」APIをそのまま再利用します。

```
server.route({
  url: '/:id',
  method: 'GET',
  preValidation: (request) => customValidation(request, logger),
  handler: (request) => {
    request.body= {
      operation: 'sql',
      sql: `SELECT * FROM dev.dog WHERE id = ${request.params.id}`
    };

    /*
     * requestWithoutAuthentication bypasses the standard HarperDB authentication.
     * YOU MUST ADD YOUR OWN preValidation method above, or this method will be available to anyone.
     */
    return hdbCore.requestWithoutAuthentication(request);
  }
});
```

## 登録エンドポイント

デフォルトの「POST /」APIをベースに、認証（preValidation）とhandler（ロジック処理）を以下のように変更します。

```
server.route({
  url: '/',
  method: 'POST',
  preValidation: (request) => customValidation(request, logger),
  handler: (request) => {
    request.body= {
      operation: 'sql',
      sql: `INSERT INTO dev.dog (adorable, age, breed_id, dog_name, owner_name, weight_lbs)
        VALUES('${request.body.adorable}', '${request.body.age}', '${request.body.breed_id}', '${request.body.dog_name}', '${request.body.owner_name}', '${request.body.weight_lbs}')`
    };

    return hdbCore.requestWithoutAuthentication(request);
  }
});
```
id と \_\_createdtime__　と \_\_updatedtime__ は自動に挿入されます。

## 更新エンドポイント

既存情報を更新する為、「PUT /{id}」APIを作成します。
リクエストの本体に"id"情報がありませんから、リクエストパラメータのidを取得して、本体に設定します。
\_\_updatedtime__は自動更新されます。

```
server.route({
  url: '/:id',
  method: 'PUT',
  handler: (request) => putHandler(request, hdbCore),
});

const putHandler = async (request, hdbCore) => {
  const put_query_table = request.body;

  put_query_table['id'] = request.params.id;

  request.body= {
    operation: 'update',
    schema: 'dev',
    table: 'dog',
    records: [put_query_table],
  };

  return hdbCore.requestWithoutAuthentication(request);
}
```

## 削除エンドポイント

リクエストパラメータで指定されるidのレコードの削除を行います。

```
server.route({
  url: '/:id',
  method: 'DELETE',
  handler: (request) => {
    request.body= {
      operation: 'sql',
      sql: `DELETE FROM dev.dog WHERE id='${request.params.id}'`
    };

    return hdbCore.requestWithoutAuthentication(request);
  }
});
```

## REST APIを検証

カスタム関数画面の左下に「Custom Functions Server URL」にテーブル名を付けたら、REST APIのurlになります。

![サーバURL](https://res.cloudinary.com/dsoombpif/image/upload/v1685112009/7_Server_URL_otugz4.png)

今回は以下のurlになります。

https://functions-demo1-taro.harperdbcloud.com/dog

PostmanなどのRest APIクライアントツールでAPIを検証できます。
以下のことを注意してください。
- インスタンスを作成する時、管理者ユーザの情報をベーシック認証に使用します。
- POST/PUT APIに「Content-Type: application/json」ヘッダを設定することが必要です。

![Postman](https://res.cloudinary.com/dsoombpif/image/upload/v1685112009/8_Postman_eynyhm.png)

HarperDB のカスタム関数を使用して動的な REST API を作成しました。 REST API と HarperDB を組み合わせることで、必要なサーバーの数が減り、スタックが折りたたまれるため、プロジェクトが大幅に高速化されます。