Create an API

Create an fast and easy to use API using AbyssMonitor features

AbyssMonitor provide tools to setup an easy API with NodeJS and TypeScript. Tools are designed to works with Express.

Setup

Create your first Middleware

import { Request, Response, NextFunction } from 'express';
import * as contentType from 'content-type';
import { IMonitorLocals, Logger, Middleware } from '@abyss-project/monitor';

export const ALLOWED_REQUEST_TYPES = [
  'application/json',
  'multipart/form-data',
  'application/x-www-form-urlencoded',
];

@Middleware()
export default class MyMiddleware {
  private static readonly logger = new Logger({});

  public async run(
    req: Request,
    res: Response<unknown, IMonitorLocals>,
    next: NextFunction,
  ): Promise<void> {
    if (req.headers['content-type']) {
      const contentT = contentType.parse({ headers: req.headers });

      if (!ALLOWED_REQUEST_TYPES.includes(contentT.type)) {
        // Throw an error because invalid request type
      }
    }

    next();
  }
}

Create your first Controller

import { Request, Response } from 'express';
import { Controller, Get, IMonitorLocals, Logger, Middlewares } from '@abyss-project/monitor';
import MyMiddleware from './../middlewares/my-middleware.middleware.ts'
@Controller({ prefixPath: '/' })
@Middlewares([MyMiddleware])
export default class MyController {
  private static readonly logger = new Logger({});

  @Get({
    path: '/hello-world',
  })
  @Middlewares([])
  async helloWorld(
    req: Request<Record<string, never>, string, void>,
    res: Response<string, IMonitorLocals>,
  ): Promise<void> {
    res.send(`Hello world !`);
  }
}

Create the Express Application

import {
  IMonitorLocals,
  contextMiddleware,
  controllerLoader,
  loggerEndpointMiddleware,
  loggerSetupMiddleware,
  Logger,
} from '@abyss-project/monitor';
import express, { Response, Request, NextFunction, Router } from 'express';
import { json, urlencoded } from 'body-parser';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import helmet from 'helmet';
import compression from 'compression';
import swaggerUi from 'swagger-ui-express';
import MyController from './controllers/my-controller.controller.ts';
import MyMiddleware from './middlewares/my-middleware.middleware.ts';
require('express-async-errors');

const PREFIX = '/api';
const PORT = 5000;

const apiLogger = new Logger({
  shouldDisableRemoteLogging: process.env.NODE_ENV === 'DEVELOPMENT',
});

const init = async (): Promise<express.Application> => {
  const app = express();
  // Adding the ContextMiddleware
  app.use(contextMiddleware);

  // Disabling the PoweredBy Express header
  app.disable('x-powered-by');

  // Enabling CORS and set kind of request my API will accept because
  // I want to make this API public
  app.use(cors());
  app.use((req: Request, res: Response<unknown, ILocals>, next: NextFunction) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization',
    );
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
    res.setHeader('Access-Control-Expose-Headers', 'Content-disposition, filename');
    next();
  });

  app.use(urlencoded({ extended: true }));
  app.use(json());
  app.use(cookieParser());
  app.use(helmet());
  app.use(compression());

  // Setting logger middleware
  app.use(loggerSetupMiddleware);
  app.use((req, res: Response<unknown, IMonitorLocals>, next) =>
    loggerEndpointMiddleware(apiLogger, req, res, next),
  );

  // Setting up the swagger
  const {
    swagger: { tags, paths },
  } = await controllerLoader(app, {
    prefix: PREFIX,
    router: Router,
    middlewares: [MyMiddleware],
    controllers: [MyController],
  });

  app.use(
    (error: Error, _req: Request, _res: Response<unknown, IMonitorLocals>, _next: NextFunction) => {
      // Do what you want with the error
      apiLogger.error(error);
    },
  );

  app
    .listen(PORT, () => {
      apiLogger.info(`API started on port ${PORT}`);
    })
    .on('error', (error) => {
      apiLogger.error(`API failed to start. Error: ${error}`);
    });

  const defaultSwagger = {
    openapi: '3.0.3',
    info: {
      title: 'My First API',
      description: '',
      version: '1.0',
      termsOfService: 'http://swagger.io/terms/',
      contact: {
        email: 'apiteam@swagger.io',
      },
      license: {
        name: 'Apache 2.0',
      },
      url: 'http://www.apache.org/licenses/LICENSE-2.0.html',
    },
    produces: ['application/json'],
    host: `http://localhost:${PORT}`,
    basePath: PREFIX,
    tags,
    paths,
  };

  app.use(
    '/swagger',
    (req: Request, res: Response<unknown, IMonitorLocals>, next: NextFunction) => {
      // Disabling the log on swagger endpoint to not spam with useless logs
      res.locals.shouldNotPublishLog = true;
      next();
    },
    swaggerUi.serve,
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    swaggerUi.setup(defaultSwagger),
  );

  return app;
};

await init();

Last updated