npm package: @iucteam/dino-ai-express
Description: REST implementation of APAC Protocol based on DinO Express
Author: Quirino Brizi
Latest version: 0.0.7

## DinO Express

> :warning: Starting from release 1.0.5 dino-express provide dino-serverless features as well, as a result dino-serverless will not receive any more updates. If you are using dino-express < 1.0.5 please migrate to dino-express >= 1.0.5 following the information provided [here](https://gitlab.com/codesketch/dino-serverless) to update the your entrypoint.

DinO Express's aim is to create a configuration first framework for exposing web APIs. The basic idea os that the first step of development starts with defining your Swagger/OpenAPI definition and provide it to DinO Express which will map your API and connect directly your code using the standard operationId defined for each API, this allow you to focus on your business requirements and the aspects that matters for your application leaving the boilerplate to DinO Express.

In order to be able to connect your Swagger/OpenAPI definition with your code seamlessly DinO Express define the concept of Interface, an interface is a Component on [DinO](https://gitlab.com/codesketch/dino) world which responsibility is to accept the input from the users and propagate, after the required checks are performed, it to your services.

An example of how DinE Express works is provided on the **examples/json** folder, you can run it using the following command:

```bash
DINO_CONTEXT_ROOT=examples/json DINO_CONFIG_PATH=examples/json/config.json node examples/json/main.js
```

DinO Express integrate with Swagger UI, this allow you to easily test your APIs and provide a clear interface for documentation, the Swagger UI will ba accessible at http://localhost:3030/api-docs or in general http[s]://hostname[:port]/api-docs.

## Configuration

### API configuration

API configuration is primarily done via OpenAPI 3.0 definition. Some aspects are configured via a configuration file.

### Service Configuration

Service configuration can be defined via DINO_CONFIG_PATH environment variable, configuration parameters are described below:

```json
{
  "application": {
    "name": "The name of the application, will be used as identifier for logging, events and any other identification based activities, if not provided defaults to OpenAPI info.title field"
  },
  "dino": {
    "active": {
      "profiles": "activate one or more runtime profiles, if more than one needs to be activated, provide a comma separated list of active profiles"
    },
    "api": {
      "validation": {
        "enabled": "true|false flag enable or disable api request/response validation",
        "configuration": "an object providing express-openapi-validator validation options"
      },
      "handler": {
        "type": "defines how parameters are provided to the method handling the request, valid options are proxy and request. if set to proxy destructured properties will be provided"
      }
    },
    "cloud": {
      "integration": "define the integration type when deployed as a lambda integrating with AWS API Gateway, allowed values are method default, or proxy",
      "provider": "The cloud provider, supported are aws and google",
      "service": "The cloud service used to run the application, supported value are lambda for aws and function for google, running as a standalone application does not require this configuration"
    },
    "environment": "define the environment the application is running on",
    "openapi": {
      "descriptor": {
        "path": "The routing configuration path",
        "provider": "The provider for the openapi configuration only supported is filesystem"
      }
    },
    "security": {
      "enabled": "true|false flag enables security aspects, this feature is under active implementation, additional features will come",
      "https": {
        "enabled": "a flag indicating if https should be configured",
        "config": "HTTPS configuration object accepts all configuration provided by https module as defined at https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener"
      }
    },
    "observability": {
      "enabled": "true|false enable or disable application observability, application lifecycle events",
      "eventEmitter": "the name of the event emitter to use, defaults to logEventEmitter, the name will be used to resolve the instance from the application context meaning that a configuration class should be created that makes the eventEmitter available",
      "batchSize": "the number of application event to batch before emitting, defaults to 1"
    },
    "server": {
      "docs": "the path for the swagger-ui, defaults to /api-docs",
      "expose": "the type of apis exposed by the application valid values are api, event, mixed",
      "monitoring": {
        "enabled": "true|false flag enables application monitoring, when enabled a new /monit endpoint is automatically exposed",
        "co2": "true|false flag enables co2 emission monitoring"
      },
      "payloadSize": "the maximum size for the payload, default to 100kb",
      "path": "the base path for the server defaults to /",
      "port": "the port the server will be exposed, defaults to 3030",
      "request": {
        "forceBase64Decode": {
          "enabled": "true|false flag enables force decode the first level of the incoming request if encoded as base64, decompress and parse from JSON if needed. Assumes that the string is compressed and after base64 encoded",
          "paths": "array of paths to decode"
        }
      },
      "response": {
        "asBase64": "true|false flag enables encoding response as base64"
      },
      "type": "The type of exposed server, valid options are standalone and embedded, deprecated options are express and serverless"
    }
  }
}
```

### Monitoring

If enabled an additional endpoint `/monitor` is exposed that provides useful information about the application status.

Exposed information are:

1. UP/DOWN status
2. Per-API cache - when enabled - information
3. CO2eq runtime emissions if enabled via the `dino.server.monitoring.co2` configuration. CO2eq monitoring is executed using the [CO2.js library provided by The Green Web Foundation](https://developers.thegreenwebfoundation.org/co2js/overview/)

Monitoring is enabled by default and can be controlled enabled/disabled using the `dino.server.monitoring.enabled` configuration.

#### Example

```json
{
  "dino": {
    "monitoring": {
      "enabled": true|false,
      "c02": true|false
    }
  }
}
```

### Caching

Dino-express uses [apicache-plus](https://www.npmjs.com/package/apicache-plus) module to provide caching functionalities. Caching is enabled adding the `cache` directive as part of the API definition, available configuration aspects are:

| Parameter        | Description                                                                                                   | Default    |
| ---------------- | ------------------------------------------------------------------------------------------------------------- | ---------- |
| ttl              | The TTL of the cache for this API                                                                             | 30 minutes |
| debug            | Enable debug statements for on console                                                                        | false      |
| trackPerformance | Enable performance tracking for the API cache, performance monitoring can be observed via `/monitor` endpoint | true       |
| isBypassable     | Allows to bypass cache by requesting with Cache-Control: no-store header                                      | true       |

#### Example

```yaml
---
paths:
  /uuid:
    get:
      summary: Get a UUID
      operationId: getUUID
      tags:
        - uuid
      parameters: {}
      x-dino-express-cache:
        ttl: 30 Seconds
        debug: false
        trackPerformance: true
        isBypassable: true
      responses:
        '200':
          description: An object containing a UUID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UUID'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
```

### Access control policies

Dino-express proposes out ot the box a quota and rate limiting policies that allows to manage access to the APIs, policies can be configured via OpenAPIs, using x-dino-express-policies, as following:

- **Rate Limit**, spike arrest policy helps protecting the backend against spikes of traffic or Denial of Service attacks, it should not be used to control or limit the number of requests that are received by the backend in a specific time window, for this a quota policy should be used. Configuration parameters for the policy are:

  - interval, the interval at which the spike arrest should be reset expressed in ms
  - allow, the number of requests that are allowed inside the window interval

  When the policy is triggered and the requests is denied a 429 HTTP response code is returned with message "Too Many Requests".

  The rate window is calculated as (interval/1000)/allow this allows to segregate requests in spike windows of a specific duration, i.e if interval is set to 60000 (one minute) and allow is set to 30 (30 allow request each minute) the spike window duration will be 2 seconds meaning that only one request is allowed to the backend every 2 seconds.

  The policy will count requests based on the client IP Address.

- **Quota**, quota policy helps limit the amount of requests that a client can make to the backend over a specific amount of time, it should not be used to protect the backend against spikes. Configuration parameters for the policy are:

  - resetInterval, the interval at which the quotas should be reset expressed in ms
  - window, the time window the quota should be defined for expressed in ms
  - allow, the number of requests that are allowed inside the window interval

When the policy is triggered and the requests is denied a 429 HTTP response code is returned with message "Quota Exceeded".
The policy will count requests based on the client IP Address.

### Cors

Dino Express allows to configure Cors on a per-api bases using the x-dino-express-cors object, the configuration is provided as described at https://expressjs.com/en/resources/middleware/cors.html.

If the x-dino-express-cors object is not defined CORS will not be enabled, instead will be explicitly disabled using the configuration `{ origin: false }` as described [here](https://expressjs.com/en/resources/middleware/cors.html#configuration-options).

#### Example

```yaml
---
paths:
  /uuid:
    get:
      summary: Get a UUID
      operationId: getUUID
      tags:
        - uuid
      parameters: {}
      x-dino-express-cors:
        origin: "*",
        methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
        preflightContinue: false,
        optionsSuccessStatus: 204
      x-dino-express-policies:
        rate-limit:
          name: rateLimitPolicy
          configuration:
            allow: 1
            interval: 1000
        quota:
          name: quotaPolicy
          configuration:
            allow: 2
            window: 10000
            resetInterval: 30000
      responses:
        '200':
          description: An object containing a UUID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UUID'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
```

## Service Configuration

```json
{
  "application": {
    "name": "The name of the application, will be used as identifier for logging, events and any other identification based activities, if not provided defaults to OpenAPI info.title field"
  },
  "dino": {
    "active": {
      "profiles": "activate one or more runtime profiles, if more than one needs to be activated, provide a comma separated list of active profiles"
    },
    "api": {
      "validation": {
        "enabled": "true|false flag enable or disable api request/response validation",
        "configuration": "an object providing express-openapi-validator validation options"
      },
      "handler": {
        "type": "defines how parameters are provided to the method handling the request, valid options are proxy and request. if set to proxy destructured properties will be provided"
      }
    },
    "cloud": {
      "integration": "define the integration type when deployed as a lambda integrating with AWS API Gateway, allowed values are method default, or proxy",
      "provider": "The cloud provider, supported are aws and google",
      "service": "The cloud service used to run the application, supported value are lambda for aws and function for google, running as a standalone application does not require this configuration"
    },
    "environment": "define the environment the application is running on",
    "openapi": {
      "descriptor": {
        "path": "The routing configuration path",
        "provider": "The provider for the openapi configuration only supported is filesystem"
      }
    },
    "security": {
      "enabled": "true|false flag enables security aspects, this feature is under active implementation, additional features will come",
      "https": {
        "enabled": "a flag indicating if https should be configured",
        "config": "HTTPS configuration object accepts all configuration provided by https module as defined at https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener"
      }
    },
    "observability": {
      "enabled": "true|false enable or disable application observability, application lifecycle events",
      "eventEmitter": "the name of the event emitter to use, defaults to logEventEmitter, the name will be used to resolve the instance from the application context meaning that a configuration class should be created that makes the eventEmitter available",
      "batchSize": "the number of application event to batch before emitting, defaults to 1"
    },
    "server": {
      "docs": "the path for the swagger-ui, defaults to /api-docs",
      "expose": "the type of apis exposed by the application valid values are api, event, mixed",
      "monitoring": {
        "enabled": "true|false flag enables application monitoring, when enabled a new /monit endpoint is automatically exposed",
        "co2": "true|false flag enables co2 emission monitoring"
      },
      "payloadSize": "the maximum size for the payload, default to 100kb",
      "path": "the base path for the server defaults to /",
      "port": "the port the server will be exposed, defaults to 3030",
      "request": {
        "forceBase64Decode": {
          "enabled": "true|false flag enables force decode the first level of the incoming request if encoded as base64",
          "paths": "array of paths to decode"
        }
      },
      "response": {
        "asBase64": "true|false flag enables encoding response as base64"
      },
      "type": "The type of exposed server, valid options are standalone and embedded, deprecated options are express and serverless"
    }
  }
}
```

## Roadmap

- Security validation based on Swagger/OpenAPI definition
- Better documentation