# rest-hapi-gen

> RESTHapi Gen is a @hapijs/hapi plugin which generates a CRUD RESTful API from a given @hapijs/joi model.

Latest version **3.1.2** (published 2023-06-13) · MIT license · 0 weekly downloads

## Install

```sh
npm install rest-hapi-gen
pnpm add rest-hapi-gen
yarn add rest-hapi-gen
bun add rest-hapi-gen
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.1.2 |
| Published | 2023-06-13 |
| First published | 2019-11-12 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 10 |
| Unpacked size | 174.3 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| Author | Daniel Arteaga |
| Maintainers | dani8art |
| Keywords | hapi, hapi-plugin, joi, api, restful, rest |

## Links

- npm: https://www.npmjs.com/package/rest-hapi-gen
- npm.io page: https://npm.io/package/rest-hapi-gen

## Dependencies (10)

- [joi](https://npm.io/package/joi.md) ^17.7.0
- [uuid](https://npm.io/package/uuid.md) ^9.0.0
- [lodash](https://npm.io/package/lodash.md) ^4.17.21
- [joigoose](https://npm.io/package/joigoose.md) ^8.0.2
- [mongoose](https://npm.io/package/mongoose.md) ^6.7.2
- [@hapi/yar](https://npm.io/package/@hapi/yar.md) ^11.0.0
- [pluralize](https://npm.io/package/pluralize.md) ^8.0.0
- [@hapi/boom](https://npm.io/package/@hapi/boom.md) ^10.0.0
- [@hapi/wreck](https://npm.io/package/@hapi/wreck.md) ^18.0.0
- [keycloak-connect](https://npm.io/package/keycloak-connect.md) ^21.0.1

## Alternatives

- [launchdarkly-js-client-sdk](https://npm.io/package/launchdarkly-js-client-sdk.md) — 2.5M weekly downloads
- [@elastic/elasticsearch](https://npm.io/package/@elastic/elasticsearch.md) — 2.1M weekly downloads
- [@c8y/client](https://npm.io/package/@c8y/client.md) — 15.3K weekly downloads
- [@signaldb/maverickjs](https://npm.io/package/@signaldb/maverickjs.md) — 1.7K weekly downloads
- [@bbc/http-transport-cache](https://npm.io/package/@bbc/http-transport-cache.md) — 1.2K weekly downloads

## Recent versions

- 3.1.2 (latest) — 2023-06-13
- 3.1.1 — 2023-06-13
- 3.1.0 — 2023-03-31
- 3.0.2 — 2023-03-13
- 3.0.1 — 2023-03-13
- 3.0.0 — 2023-03-13
- 2.5.1 — 2023-01-03
- 2.5.0 — 2022-12-11
- 2.4.0 — 2022-12-09
- 2.3.0 — 2022-11-18
- 2.2.1 — 2021-08-07
- 2.2.0 — 2020-12-27
- 2.1.2 — 2020-12-12
- 2.1.1 — 2020-11-18
- 2.1.0 — 2020-11-17
- … 8 more at https://npm.io/package/rest-hapi-gen/versions

## README

# RESTHapi Gen

[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![npm version](https://img.shields.io/npm/v/rest-hapi-gen.svg?style=flat)](https://www.npmjs.com/package/rest-hapi-gen) [![CircleCI](https://circleci.com/gh/dani8art/rest-hapi-gen.svg?style=svg)](https://circleci.com/gh/dani8art/rest-hapi-gen) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)]() [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest) [![jest](https://facebook.github.io/jest/img/jest-badge.svg)](https://github.com/facebook/jest)

> RESTHapi Gen is a [@hapijs/hapi](https://github.com/hapijs/hapi) plugin which generates a CRUD RESTful API from a given [joi](https://github.com/hapijs/joi) model.

### Compatibility

| RESTHapi Gen version | Hapi JS version       | Joi Version        |
| -------------------- | --------------------- | ------------------ |
| `2.x.x` and `3.x.x`  | `20.x.x` and `21.x.x` | `joi^17.x.x`       |
| `1.x.x`              | `19.x.x`              | `@hapi/joi^17.x.x` |
| `0.x.x`              | `18.x.x`              | `@hapi/joi^15.x.x` |

## TL;DR;

```
$ npm i @hapi/hapi joi mongoose rest-hapi-gen
```

```javascript
const Hapi = require('@hapi/hapi');
const Joi = require('joi');
const Mongoose = require('mongoose');

const RestHapiGen = require('rest-hapi-gen');

(async () => {
  await Mongoose.connect('mongodb://localhost:27017/testdb', { useNewUrlParser: true, useUnifiedTopology: true });

  const server = Hapi.server({ port: 4000 });

  const petsCollectionConf = {
    collection: { name: 'pets' },
    schema: Joi.object({
      name: Joi.string().required(),
      tags: Joi.array().items(Joi.string()).default([]),
    }),
  };

  await server.register([{ plugin: RestHapiGen, options: petsCollectionConf }]);
  await server.start();

  console.log('Server running on %s', server.info.uri);
})();
```

## Plugin configuration

| Option                            | Type       | Description                                                                                                                        |
| --------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| auth.enabled                      | `boolean`  | `Optional` Whether to activate auth or not. Default: `false`                                                                       |
| auth.client.id                    | `string`   | `Required` OAuth 2.0 client id. It is required if `$.auth.enabled === true`                                                        |
| auth.client.secret                | `string`   | `Required` OAuth 2.0 client secret. It is required if `$.auth.enabled === true`                                                    |
| auth.client.kind                  | `string`   | `Optional` OAuth 2.0 server kind. Default: `keycloak`                                                                              |
| auth.scope.read                   | `string[]` | `Optional` OAuth 2.0 required scope list to access read actions. Default `false`                                                   |
| auth.scope.write                  | `string[]` | `Optional` OAuth 2.0 required scope list to access write actions. Default `false`                                                  |
| auth.server.url                   | `string`   | `Required` OAuth 2.0 server. It is required if `$.auth.enabled === true`                                                           |
| auth.server.realm                 | `string`   | `Optional` OAuth 2.0 server realm. Default: `master`                                                                               |
| auth.session.cookie.name          | `string`   | `Optional` Name for the session cookie. Default: `rest-hapi-gen-session`                                                           |
| auth.session.enabled              | `boolean`  | `Optional` Whether to enable session or just bearer only auth mechanism. Default: `true`                                           |
| auth.session.password             | `string`   | `Optional` The session encryption password. Default: Random generated                                                              |
| basePath                          | `string`   | `Optional` Base path where the CRUD endpoints are attached. Default: `'/'`                                                         |
| collection.name                   | `string`   | `Required` Name for the collection that is going to be created.                                                                    |
| collection.pages.limit            | `number`   | `Optional` Default max limit for collection queries, it will be overrided if the API user uses `collection?limit=x`. Default: `10` |
| health.enabled                    | `boolean`  | `Optional` Whether to enable a health endpoint. Default: `true`                                                                    |
| health.path                       | `string`   | `Optional` Target path where the health endpoint will be set, it must start with `/`. Default: `/_healthz`                         |
| overrides.actions.GET_COLLECTION  | `Function` | `Optional` Async function that will override the default handler for GET_COLLECTION action                                         |
| overrides.actions.GET_RESOURCE    | `Function` | `Optional` Async function that will override the default handler for GET_RESOURCE action                                           |
| overrides.actions.CREATE_RESOURCE | `Function` | `Optional` Async function that will override the default handler for CREATE_RESOURCE action                                        |
| overrides.actions.UPDATE_RESOURCE | `Function` | `Optional` Async function that will override the default handler for UPDATE_RESOURCE action                                        |
| overrides.actions.DELETE_RESOURCE | `Function` | `Optional` Async function that will override the default handler for DELETE_RESOURCE action                                        |
| rootPathRedirect                  | `boolean`  | `Optional` Whether redirect from root path (`/`) to `basePath` path. Default: `false`                                              |
| schema                            | `Joi`      | `Required` Joi schema for the collection that is created.                                                                          |
| tls                               | `boolean`  | `Optional` Whether the server is using TLS externally/internally or not. Default: `false`                                          |

### Override an action

If an action needs to be overrided, you must provide an `async function` that will be executed instead of the default one. This function will receive three args: `request` that will be a @hapijs/hapi [request object](https://hapi.dev/api/?v=20.0.2#request), `h` that will be a @hapijs/hapi [request toolkit](https://hapi.dev/api/?v=20.0.2#response-toolkit) and a `model` that will be a [mongoose model](https://mongoosejs.com/docs/models.html) which is based on the given schema.

> NOTE: Your custom function must return an object that must to be valid against the **Joi** schema otherwise the server will return an internal server error.

```js
...
const { ActionType } = RestHapiGen;
...
  const petsCollectionConf = {
    collection: { name: 'pets' },
    schema: Joi.object({
      name: Joi.string().required(),
      tags: Joi.array().items(Joi.string()).default([])
    }),
    // Override actions
    overrides: {
      actions: {
        // Override GET collection action
        [ActionType.GET_COLLECTION]: async (request, h, model) => {
          return await model.find();
        },
      },
    },
  };
...
```

In addition, you could configure Hapi server adding `debug.request` so you can see schema validation errors, to do so you must apply the following configuration to your Hapi server

```js
...
const server = Hapi.server({
  port: 4000,
  debug: {
    request: ['*'],
  },
});
...
```

### Configure authentication

Currently, RESTHapi Gen only support `keycloak` as authentication provider, a generated resource can be protected using OAuth 2.0 and keycloak server, see the following example.

```javascript
const petsCollectionConf = {
  collection: { name: 'pets' },
  schema: Joi.object({
    name: Joi.string().required(),
    tags: Joi.array().items(Joi.string()).default([]),
  }),
  auth: {
    enabled: true,
    server: { url: 'https://auth.example.io', realm: 'pets' },
    client: { id: 'example-client', secret: 'example-client-secret' },
    scope: { read: ['pets:ro'], write: ['pets:rw'] },
  },
};
```

## Deploy MongoDB

**Docker**

```shell
$ docker run -d --rm --name mymongo -p 27017:27017 mongo
```

**Docker Compose**

```yaml
version: '3.7'

services:
  mongo:
    image: mongo
    ports:
      - 27017:27017
```

```shell
$ curl -sSL https://raw.githubusercontent.com/dani8art/rest-hapi-gen/master/docker-compose.yaml > docker-compose.yaml
$ docker-compose up -d
```

## License

RESTHapi Gen is [MIT licensed](./LICENSE).

---
_Source: https://npm.io/package/rest-hapi-gen · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
