2.0.0 • Published 3 years ago

@gearedminds/tsed-api-support v2.0.0

Weekly downloads
3
License
WTFPL
Repository
-
Last release
3 years ago

TSED Api Support

This module is used to secure any nodejs express API using TSED node module (https://tsed.io/). It handles :

Each one is a middleware.

It also provides a set of HTTP errors, Probes, a Logger factory and a swagger generator tool (related to TSED).

Token introspection service

This service is used to introspect the provided user token.

Builder options required by this middleware :

    // skip all checks if set to false
    authenticationMW_enabled: boolean;
    // URL of the oAuth service
    authenticationMW_oauthServiceURL: string;
    // uri(s) for which all checks are disabled
    authenticationMW_unprotectedPaths: string[];

If the user token is not successfully introspected or the authentication failed, a 401 error code is returned.

Permit service

This service is used to get roles of the calling user for a given application

After getting roles, the middleware checks if the method & the path are authorized for this user (crossing data with returned roles). If the endpoint does not require specific permission, the user is authorized by default.

Builder options required by this middleware :

    // skip all checks if set to false
    accessControlMW_enabled: boolean;
    // skip all Headers checks if set to false
    headerMW_enabled: boolean;
    // URL of the permit service
    accessControlMW_permissionServiceURL: string;
    // uri(s) for which all checks are disabled
    accessControlMW_unprotectedPaths: string[];
    // roles/path/method mapping to know if the user is authorized to access this endpoint
    accessControlMW_roleMappings: any[];
    // the name of the application
    accessControlMW_enclosingAppName: string;
    // x-api-key of calling api
    accessControlMW_enclosingAppApiKey: string;

Header service

This service is used to get information about enclosing app and user

Builder options required by this middleware :

    // skip all Headers checks if set to false
    headerMW_enabled: boolean;

MuteAllRoutesMiddleware

This middleware is used to allow the start of an API when database is not totally up (migration in progress)

It allows to serve the /_health only endpoint when some migrations are running

    // enable the middleware
    muteAllRoutesMW_enabled: boolean;

When using this middleware, the ApiStatusProbe will now show a warning status when the API is not totally up

When you're ready to unleash your routes (allow access to any other routes than just /_health), you have the responsibility to call the unMute method of this middleware.

Middlewares.MuteAllRoutesMiddleware.unMute();

While this method is not called, all another route than /_health will return a 503 error code

HTTP Errors

By importing Errors from this module, the following errors are available:

  • NoContentFoundError returning a 204 response. It is often used for empty search result.
  • ValidationError returning a 400 response. It is often used for request parameters/body validation errors.
  • NotFoundError returning a 404 response. It is often used when getting/updating/deleting an unknown resource.
  • ConflictError returning a 409 response. It is often used when updating a resource which is in conflict with another one.
  • TechnicalError returning a 500 response. It is used for internal server error.
  • ServiceUnavailableError returning a 503 response. It is used when API can't answer due to server side errors.

When combined with the ErrorTranslationMiddleware, these errors are automatically handled as valid json output with the matching status code.

Probes

Probes are used for the endpoint /_health in order to have a quick check up of an API

The model of a probe is defined as follow :

    name: string; // The name of the probe
    description: string; // A quick description
    value: any; // It's value (could be a number for a ping, or an enum, ...)
    status: "OK" | "WARNING" | "CRITICAL"; // A value that speaks for itself
    start: number; // The begin time of the probe
    end: number; // The end time of the probe

Probes are wrapped in a HealthProbeResponse

HealthProbeResponse

export interface HealthProbeResponse {
    version: string;
    probes: AbstractProbe[];
    status: ProbeStatus;
}

You can use it like this

const version = Env.getVersion();
const result: Probes.HealthProbeResponse = {
    version,
    probes: [],
    status: "OK"
};

ApiStatusProbe

This probe has en empty constructor, so you can't define its name and description Value and status are set in the constructor whith the value of the MuteAllRoutesMiddleware

  • When routes are muted, value will have the value starting and status the value WARNING
  • When routes are unmuted, value will have the value running and status the value OK

You can use it like this

ProbeFactory.getApiStatusProbe()
    .then((probe) => {
        result.probes.push(probe);
    });

In case of you're using several probes in your /_health endpoint, you can quickly find this one by searching on its name

const probes: Probes.AbstractProbe[] = res.body.probes;
const statusProbe = probes.find(probe => probe.name === Probes.ApiStatusProbe.NAME);

DbPingProbe

A probe that is used to get the response time of a database.

This probe uses the 3 states of status with default values as follows:

durationstatus
> 1sCRITICAL
> 100msWARNING
≤ 100msOK

This probe needs a Promise<number> in order to retrieve the correct status. You can set your own limit values for WARNING and CRITICAL status with optional parameters.

// MyDatabaseClass.ts
public async ping(): Promise<number> {
    const pingStart = moment();
    return this.sequelize.query("select * from types")
        .then(() => {
            const pingEnd = moment();
            return pingEnd.diff(pingStart, "milliseconds");
        })
        .catch(() => -1);
}

// HealthController.ts
ProbeFactory.getDbPingProbe(() => ping) // For default values
    .then((probe) => {
        result.probes.push(probe);
    });

const criticalPing = 2000;
const warningPing = 500;
ProbeFactory.getDbPingProbe(() => ping, criticalPing, warningPing) // For custom values
    .then((probe) => {
        result.probes.push(probe);
    });

You can find it by its name as the ApiStatusProbe

const probes: Probes.AbstractProbe[] = res.body.probes;
const dbPingProbe = probes.find(probe => probe.name === Probes.DbPingProbe.NAME);

GenericProbe

A probe in which you can define its name and description. It allows you to define your own Probes when needed

A Factory is available in order to set properly all attributes of a probe

ProbeFactory.getGenericProbe("PgDbProbe", "A simple ping of the Postgresql database", () => SequelizeManager.ping())
    .then((probe: Probes.GenericProbe) => {
        if (probe.value > 100000000) {
            probe.status = "WARNING";
        }
        probe.value = `${probe.value} nanoseconds`;
        probeResult.probes.push(probe);
    })

Logger factory

By importing Loggerfrom this module, you can get a logger with getLogger("...") method and use common logger methods on it (error, warn, debug; info, ...). The name given to getLogger(name) is traced in logs and is usefull for debug.

Swagger generator tool

The tsed-api-support swagger-file command generates the swagger.json file

Version file generator

The lib also comes with another bin that generates a version file (version.json) that could prove very handy when exposing a project's current version through an endpoint without having to embed/parse/read the whole package package.json file.

Just try the following command : > tsed-api-support version-file ./package.json > version.json

Installation

Just either add the component to your package.json file (recommended way) or issue an npm install command.

npm install @gearedminds/tsed-api-support