# Create an API

[AbyssMonitor](/abyss-monitor/abyss-monitor.md) provide tools to setup an easy API with NodeJS and TypeScript. Tools are designed to works with Express.

### Setup&#x20;

#### Create your first Middleware

```typescript
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

```typescript
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

{% code overflow="wrap" lineNumbers="true" %}

```typescript
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();

```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://abyss-project.gitbook.io/abyss-monitor/tutorials/create-an-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
