Create an API service using nestframework
Tags: nestjs, swagger, typescript, echarts
Published: 2020-01-26 09:56:32

> [Original Post](https://blog.yggdrasilts.com/create-an-api-service-using-nestframework/)

In this post, I want to show you how easy is to create a backend API using the nestframework and also, create the [swagger](https://swagger.io/) documentation.

# Table Of Contents
* [Introduction](#introduction)
* [Part 1 - Project Creation](#part-1)
  * [API Service](#api-service)
  * [Requirements](#requirements)
  * [Service Creation](#service-creation)
* [Part 2 - EchartsService Creation](#part-2)
  * [Delete Unnecessary Files](#delete-unnecessary-files)
  * [Modifying app.controller.ts file](#modifying-app-controller)
  * [Modifying app.service.ts file](#modifying-app-service)
* [Part 3 - Logger, Validations and Pipes, Handling Errors and Modules](#part-3)
  * [Logger](#logger)
  * [Validations and Pipes](#validation-and-pipes)
  * [Handling Errors](#handling-errors)
  * [Modules](#modules)
* [Part 4 - Swagger](#part-4)
* [To Sum Up](#to-sum-up)

# Introduction <a name="introduction"></a>

I have to say that I am in love with [NestJS](https://nestjs.com/) to build backend applications, services, libraries, etc. using [TypeScript](https://www.typescriptlang.org/). This framework has been the [fastest-growing nodejs framework in 2019](https://risingstars.js.org/2019/en/#section-nodejs-framework) due to its awesome features that, besides helps you to build your code, if you are thinking about to build medium or large services and you want it to be maintainable and scalable, also it give you a way to have your project well structured.

# Part 1 - Project Creation <a name="part-1"></a>

## API Service <a name="api-service"></a>

The service that I am going to create is a simple API service that contains 2 endpoints. Each endpoint returns a chart as image in different formats:

- */image*: Return an image as attachment.
- */image-base64*: Return an image as base64 string data.

To build the charts, I am going to use [node-echarts](https://github.com/telco2011/node-echarts) library to get [ECharts](https://echarts.apache.org/en/index.html) images in the backend world. [ECharts](https://echarts.apache.org/en/index.html) is an open-sourced JavaScript visualization tool that in my opinion, it has great options to build tons of different chart types.

> *You can check its [examples](https://echarts.apache.org/examples/en/index.html) if you don't believe me* 😛

Let's begging to create.

## Requirements <a name="requirements"></a>

- [nodejs](https://nodejs.org/en/) ([nvm](https://github.com/nvm-sh/nvm))
- [NestJS CLI](https://github.com/nestjs/nest-cli)
- [node-echarts](https://github.com/telco2011/node-echarts) (*OS package dependencies*)
- [Visual Studio Code](https://code.visualstudio.com/) (*or your preferred Code Editor / IDE*)

## Service Creation <a name="service-creation"></a>

Once all requirements are installed, I am going to use the [NestJS CLI](https://github.com/nestjs/nest-cli) to create the project structure:

```shell
odin@asgard:~/Blog $ nest new echarts-api-service -p npm
```

After the execution, I have opened the `~/Blog/echarts-api-service` folder in my [Visual Studio Code](https://code.visualstudio.com/) and this is the project structure:

![](http://blog.yggdrasilts.com/content/images/2020/01/image.png)

> *[Here](https://docs.nestjs.com/first-steps), you can see more about the [NestJS](https://nestjs.com/) project structure. I assume that you are familiar with this structure and I continue building the service.*

Now, you can run the service using `npm start` and the service will respond a `Hello World!` string doing the following request: [*http://localhost:3000*](http://localhost:3000/)*,* as you can see in the following image (*I'm using [REST Client extension](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) for [Visual Studio Code](https://code.visualstudio.com/)*).

![](http://blog.yggdrasilts.com/content/images/2020/01/image-1.png)

Before continue, I am going to add a *.prettierc* file for code formatting using [Prettier](https://prettier.io/) with the following options:

```json
{
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false,
  "trailingComma": "all",
  "printWidth": 140
}
```

And also I like to add the hot reload option to check faster my code changes. To do this, and because I am using [NestJS CLI](https://github.com/nestjs/nest-cli), it is only necessary to change the `start:dev` script inside the *package.json* as `nest start --watch --webpack`. In [NestJS Hot Reload documentation](https://docs.nestjs.com/recipes/hot-reload#hot-reload) you can see more options.

Now, I am ready to modify the code to add the above endpoints */image* and */image-base64*.

> *'End of Part 1' You can check the project code in the [part-1](https://github.com/yggdrasilts/echarts-api-service/tree/part-1) tag*

# Part 2 - EchartsService creation <a name="part-2"></a>

I am going to modify/delete all the not needed files to adapt the project in a better way.

## Delete unnecessary files <a name="delete-unnecessary-files"></a>

In my case, It is not needed to use the *app.controller.spec.ts*. I delete it.

## Modifying *app.controller.ts* file <a name="modifying-app-controller"></a>

This file is responsible for handling incoming **requests** and returning **responses** to the client and it is the site where I am going to create the endpoints to let [NestJS](https://nestjs.com/) know the code to use when receiving the requests.

```typescript
import { Controller, Post } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post('image')
  async getImage(): Promise<void> {
    console.log('getImage');
  }

  @Post('image-base64')
  async getImageInBase64(): Promise<string> {
    return 'getImageInBase64';
  }
}
```

> *More information about controllers in [NestJS Controllers documentation](https://docs.nestjs.com/controllers).*

Once modified, you can start the service again `npm run start:dev` and execute both requests:

- *POST http://localhost:3000/image*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-2.png)

- *POST http://localhost:3000/image-base64*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-3.png)

## Modifying *app.service.ts* file <a name="modifying-app-service"></a>

The service is responsible for data storage and retrieval, in my case, the service will be the chart image creator.

Because I use [ECharts](https://echarts.apache.org/en/index.html), with [node-echarts](https://github.com/telco2011/node-echarts), I am going to create a new folder called *echarts* and inside another folder called *entities*. After this, move the *app.service.ts* to this new folder *echarts* and renamed it to *echarts.service.ts*.

> *'WARN' If you use Visual Studio Code, you will see that in every change, the editor adapts the code. Take care if not and adapt the code to be compiled.*

After the changes, I am going to create the *getImage* method which has the code to create the [ECharts](https://echarts.apache.org/en/index.html) image. But first, I am going to install the necessary npm dependencies to create the method:

- `npm i --save imagemin imagemin-pngquant imagemin-jpegtran https://github.com/telco2011/node-echarts.git`
- `npm i --save-dev @types/imagemin @types/echarts`

And the method:

```typescript
async getImage(opt: Options): Promise<Buffer> {
  return buffer(
    node_echarts({
      option: opt.echartOptions,
      width: opt.options?.width || DEFAULT_IMAGE_WIDTH,
      height: opt.options?.height || DEFAULT_IMAGE_HEIGHT,
    }),
    {
      plugins: [
        imageminJpegtran(),
        imageminPngquant({
          quality: [0.6, 0.8],
        }),
      ],
    },
  );
}
```

Once all the changes are done, your code won't compile due to the compiler does not find the *Options* name. This name will be a new class with two options, one to store the [ECharts](https://echarts.apache.org/en/index.html) options to create the chart and other to store some properties to create the image that will contain the [ECharts](https://echarts.apache.org/en/index.html).

To do so, I am going to create the next 3 files:

- `src/echarts/entities/options.entity.ts`

```typescript
import { EChartOption } from 'echarts';

import { ImageOptions } from './image-options.entity';

/**
 * Class to configure echarts options.
 */
export class Options {
  echartOptions: EChartOption;

  options?: ImageOptions;
}
```

- `src/echarts/entities/image-options.entity.ts`

```typescript
/**
 * Class to configure image options.
 */
export class ImageOptions {
  // Image width
  width?: number;

  // Image height
  height?: number;

  // Download file name
  filename?: string;
}
```

> *'INFO' The file name structure is important in NestJS because it will be relevant for Part 4 of this post. It is **IMPORTANT** that the entity file name follows the next structure: [NAME].entity.ts*

- `src/echarts/constants.ts`

```typescript
/**
 * Application constants.
 */
export const DEFAULT_IMAGE_WIDTH = 600;

export const DEFAULT_IMAGE_HEIGHT = 250;

export const DEFAULT_FILENAME = 'echarts.png';
```

Finally the *echarts.service.ts* code is the following:

```typescript
import { Injectable } from '@nestjs/common';

import * as node_echarts from 'node-echarts';

import { buffer } from 'imagemin';
import imageminPngquant from 'imagemin-pngquant';
import * as imageminJpegtran from 'imagemin-jpegtran';

import { DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT } from './constants';

import { Options } from './entities/options.entity';

@Injectable()
export class EchartsService {
  /**
   * Get the echarts as image.
   *
   * @param {Options} opt {@link Options}.
   */
  async getImage(opt: Options): Promise<Buffer> {
    return buffer(
      node_echarts({
        option: opt.echartOptions,
        width: opt.options?.width || DEFAULT_IMAGE_WIDTH,
        height: opt.options?.height || DEFAULT_IMAGE_HEIGHT,
      }),
      {
        // plugins to compress the image to be sent
        plugins: [
          imageminJpegtran(),
          imageminPngquant({
            quality: [0.6, 0.8],
          }),
        ],
      },
    );
  }
}
```

After these updates, the code compiles well and you can start the server again `npm run start:dev`.

> *'HINT' If you want, you can add/modify/delete all of these files without stopping the service and you will see how the [Hot Reload feature](https://docs.nestjs.com/recipes/hot-reload) works.*

Now, I am going to connect the controller to the service to get all the functionality on. To do this, I am going to make some modifications in the *app.controller.ts* file to call the *getImage* method inside the service:

```typescript
import { Controller, Post, Header, Body, Res } from '@nestjs/common';
import { Response } from 'express';

import { HttpHeaders, MimeType, BufferUtils } from '@yggdrasilts/volundr';

import { EchartsService } from './echarts/echarts.service';
import { Options } from './echarts/entities/options.entity';
import { DEFAULT_FILENAME } from './echarts/constants';

@Controller()
export class AppController {
  constructor(private readonly echartsService: EchartsService) {}

  @Post('image')
  @Header(HttpHeaders.CONTENT_TYPE, MimeType.IMAGE.PNG)
  async getImage(@Body() opt: Options, @Res() response: Response): Promise<void> {
    const result = await this.echartsService.getImage(opt);
    response.setHeader(HttpHeaders.CONTENT_LENGTH, result.length);
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, `attachment;filename=${opt.options?.filename || DEFAULT_FILENAME}`);
    response.end(result);
  }

  @Post('image-base64')
  @Header(HttpHeaders.CONTENT_DISPOSITION, MimeType.TEXT.PLAIN)
  async getImageInBase64(@Body() opt: Options): Promise<string> {
    return BufferUtils.toBase64(await this.echartsService.getImage(opt));
  }
}
```

The code does not compile because of a dependency is not installed yet. This dependency is *[@yggdrasilts/volundr](https://github.com/yggdrasilts/volundr)*, part of our toolset. This library is a set of utilities for [TypeScript](https://www.typescriptlang.org/) developments. To compile, you only need to install it using `npm i --save @yggdrasilts/volundr`.

> *If you want to know more about it, take a look to its repository [*@yggdratilsts/volundr*](https://github.com/yggdrasilts/volundr)*

If you see the code, it is very easy to understand it because the [NestJS decorators](https://docs.nestjs.com/controllers) are very explicit.

- *@Post()* decorator indicates that both endpoints are listening POST request.
- I am using the *@Header()* decorator to set the response Headers.
- And also I am using *@Body()* decorator to get the request body to be used inside the service.

At this point, if you start the service `npm run start:dev` you will have available the wanted endpoints:

- POST *http://localhost:3000/image*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-4.png)

- POST *http://localhost:3000/image-base64*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-5.png)

> *I'm getting the *echartOptions* data from the [ECharts Example - Stacked Area Chart](https://echarts.apache.org/examples/en/editor.html?c=area-stack)*

> *'End of Part 2' You can check the project code in the [part-2](https://github.com/yggdrasilts/echarts-api-service/tree/part-2) tag*

# Part 3 - Logger, Validations and Pipes, Handling Errors and Modules <a name="part-3"></a>

Now, the application is functional but before to finish, I would like to add, and talk, about some other features that [NestJS](https://nestjs.com/) provides to create a service.

## Logger <a name="logger"></a>

In my opinion, every project should have a good logger implementation because it is the principal way to know what is happening in the flow. In this case, [NestJS](https://nestjs.com/) has a built-in text-based [Logger](https://docs.nestjs.com/techniques/logger) that is enough for our service.

To use this logger, it is only necessary to instantiate the class and start using it. For example:

```typescript
import { Controller, Get, Logger } from '@nestjs/common';

@Controller()
export class MyController {
  private readonly logger = new Logger(MyController.name);

  @Get('log-data')
  getImage(): void {
      this.logger.debug('Logging data with NestJS it's so easy...');  
  }
}
```

The service that I am creating will use this logger for the *app.controller.ts*, *body.validation.pipe.ts* and *http-exception.filter.ts*. I am going to talk about these two last files in the following parts of the post.

> *If you want to know more about how to use the [NestJS](https://nestjs.com/) logger, you can go to its [documentation](https://docs.nestjs.com/techniques/logger). Also, in the following posts, I will talk about it.*

## Validations and Pipes <a name="validations-and-pipes"></a>

Like [NestJS](https://nestjs.com/) documentation says in its [Validation section](https://docs.nestjs.com/techniques/validation), it is best practice to validate the correctness of any data sent into a web application. For this reason, I am going to use the [Object Schema Validation](https://docs.nestjs.com/pipes#object-schema-validation) and creating a custom [Pipe](https://docs.nestjs.com/pipes) to do so.

First, I am going to adapt the project installing some needed dependencies and creating and modifying some files and folders.

### Installing needed dependencies

- `npm i --save @hapi/joi`
- `npm i --save-dev @types/hapi__joi`

> [@hapi/joi](https://hapi.dev/family/joi/) lets you describe your data using a simple, intuitive, and readable language

### Creating new files and folders

- `src/pipes/body.validation.pipe.ts`

```typescript
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException, Logger } from '@nestjs/common';

import { Schema } from '@hapi/joi';

/**
 * Pipe to validate request body.
 */
@Injectable()
export class BodyValidationPipe implements PipeTransform {
  private readonly logger = new Logger(BodyValidationPipe.name);

  constructor(private readonly schema: Schema) {}

  transform(value: any, metadata: ArgumentMetadata) {
    this.logger.debug(`Input body: ${JSON.stringify(value)}`);
    const { error } = this.schema.validate(value);
    if (error) {
      this.logger.error(`Error validating body: ${JSON.stringify(error)}`);
      throw new BadRequestException(`Validation failed: ${error.message}`);
    }
    return value;
  }
}
```

#### Modifying *app.controller.ts*

```typescript
import { Controller, Post, Header, Body, Res, UsePipes, Logger } from '@nestjs/common';
import { Response } from 'express';

import { HttpHeaders, MimeType, BufferUtils } from '@yggdrasilts/volundr';

import { EchartsService } from './echarts/echarts.service';
import { Options } from './echarts/entities/options.entity';
import { DEFAULT_FILENAME, IMAGE_BODY_VALIDATION_SCHEMA } from './echarts/constants';

import { BodyValidationPipe } from './pipes/body.validation.pipe';

@Controller()
export class AppController {
  private readonly logger = new Logger(AppController.name);

  constructor(private readonly echartsService: EchartsService) {}

  @Post('image')
  @Header(HttpHeaders.CONTENT_TYPE, MimeType.IMAGE.PNG)
  @UsePipes(new BodyValidationPipe(IMAGE_BODY_VALIDATION_SCHEMA))
  async getImage(@Body() opt: Options, @Res() response: Response): Promise<void> {
    const result = await this.echartsService.getImage(opt);
    response.setHeader(HttpHeaders.CONTENT_LENGTH, result.length);
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, `attachment;filename=${opt.options?.filename || DEFAULT_FILENAME}`);
    response.end(result);
  }

  @Post('image-base64')
  @Header(HttpHeaders.CONTENT_DISPOSITION, MimeType.TEXT.PLAIN)
  @UsePipes(new BodyValidationPipe(IMAGE_BODY_VALIDATION_SCHEMA))
  async getImageInBase64(@Body() opt: Options): Promise<string> {
    return BufferUtils.toBase64(await this.echartsService.getImage(opt));
  }
}
```

#### Modifying *echarts/constants.ts*

```typescript
/**
 * Application constants.
 */
import * as Joi from '@hapi/joi';

export const DEFAULT_IMAGE_WIDTH = 600;

export const DEFAULT_IMAGE_HEIGHT = 250;

export const DEFAULT_FILENAME = 'echarts.png';

export const IMAGE_BODY_VALIDATION_SCHEMA = Joi.object({
  echartOptions: Joi.object().required(),
  options: Joi.object().optional(),
});
```

Now, if you start the service `npm run start:dev` and do a request with an invalid body, you will see an error.

- POST *http://localhost:3000/image*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-6.png)

This is a simple error handling that [NestJS](https://nestjs.com/) provides by default but I like to customize it and show more readable error using [NestJS Exceptions Filters](https://docs.nestjs.com/exception-filters).

> *'End of Part 3.1' You can check the project code in the [part-3.1](https://github.com/yggdrasilts/echarts-api-service/tree/part-3.1) tag*

### Handling Errors <a name="handling-errors"></a>

First, I am going to create my custom Exception Filter and activated it in the global-scope to manage all endpoint errors.

To do this purpose, I am going to create a new folder and file called `src/exceptions/http-exception.filter.ts`

```typescript
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, Logger } from '@nestjs/common';
import { Request, Response } from 'express';

import { HttpHeaders, MimeType } from '@yggdrasilts/volundr';

/**
 * Filter to catch HttpException manipulating the response to get understandable response.
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(HttpExceptionFilter.name);

  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();
    const message = exception.message;

    const errorData = {
      timestamp: new Date().toISOString(),
      message,
      details: {
        request: {
          method: request.method,
          query: request.query,
          body: request.body,
        },
        path: request.url,
      },
    };
    this.logger.error(`${JSON.stringify(errorData)}`);
    response.setHeader(HttpHeaders.CONTENT_TYPE, MimeType.APPLICATION.JSON);
    response.status(status).json(errorData);
  }
}
```

This filter is similar to the one in [NestJS Exception Filter section](https://docs.nestjs.com/exception-filters#exception-filters-1), but I have made some personal customizations to get more information in the error data.

After the file creation, it is needed to activate this filter in the global-scope. To do so, I am going to modify the `main.js` file:

```typescript
import { NestFactory } from '@nestjs/core';

import { AppModule } from './app.module';

import { HttpExceptionFilter } from './exceptions/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new HttpExceptionFilter());

  await app.listen(3000);
}
bootstrap();
```

Now, you can start the service again `npm run start:dev` and see how the error has changed.

- POST *http://localhost:3000/image*

![](http://blog.yggdrasilts.com/content/images/2020/01/image-7.png)

> *'End of Part 3.2' You can check the project code in the [part-3.2](https://github.com/yggdrasilts/echarts-api-service/tree/part-3.2) tag*

### Modules <a name="modules"></a>

To finalize this part, I am going to use [modules](https://docs.nestjs.com/modules) to follow the structure that NestJS propose because I think this structure it is very intuitive to follow having different modules with their own functionality.

To do this, I am going to create the `src/echarts/echarts.module.ts` file:

```typescript
import { Module } from '@nestjs/common';

import { EchartsService } from './echarts.service';

@Module({
  providers: [EchartsService],
  exports: [EchartsService],
})
export class EchartsModule {}
```

And modify the *app.module.ts* file to import this new module instead of importing the *EcharsService* directly:

```typescript
import { Module } from '@nestjs/common';

import { EchartsModule } from './echarts/echarts.module';

import { AppController } from './app.controller';

@Module({
  imports: [EchartsModule],
  controllers: [AppController],
})
export class AppModule {}
```

Finally, I am going to check if the service continues working as before executing `npm run start:dev` and checking the endpoints with the REST Client VS extension like at the end of Part 2.

> *'End of Part 3.3' You can check the project code in the [part-3.3](https://github.com/yggdrasilts/echarts-api-service/tree/part-3.3) tag*

# Part 4 - Swagger <a name="part-4"></a>

Providing good documentation for every API is essential if we want to be used by other people. There are lots of [alternatives](https://alternativeto.net/software/swagger-io/) to create this documentation but [NestJS](https://nestjs.com/) has an awesome [module](https://docs.nestjs.com/recipes/swagger) that use [Swagger](https://swagger.io/) for this purpose.

> *[Kamil Mysliwiec](https://twitter.com/kammysliwiec), [NestJS](https://nestjs.com/) creator, has written a great [article](https://trilon.io/blog/nestjs-swagger-4-whats-new) talking about the new [NestJS](https://nestjs.com/) Swagger module features. I recommend you to read it, it is very interesting.*

Before to start documenting, it is necessary to install the [NestJS Swagger module](https://docs.nestjs.com/recipes/swagger):

```shell-session
odin@asgard:~/Blog $ npm install --save @nestjs/swagger swagger-ui-express
```

Once installed, we bootstrap the service modifying the *main.ts* file like the documentation sais:

```typescript
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

import { AppModule } from './app.module';

import { HttpExceptionFilter } from './exceptions/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new HttpExceptionFilter());

  const options = new DocumentBuilder()
    .setTitle('Echarts API')
    .setDescription('API to get charts, using echartsjs, as image file.')
    .setExternalDoc('More about echartsjs', 'https://echarts.apache.org/en/index.html')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);

  await app.listen(3000);
}
bootstrap();
```

Now we can start the service `npm run start:dev` and automatically we will have the Swagger documentation at http://localhost:3000/api:

![](http://blog.yggdrasilts.com/content/images/2020/01/image-10.png)

> *Don't you think this is so easy? 😉*

If you are read the above [Kamil Mysliwiec](https://twitter.com/kammysliwiec)'s [post](https://trilon.io/blog/nestjs-swagger-4-whats-new), with the new [NestJS Swagger plugin](https://docs.nestjs.com/recipes/swagger#plugin) version, the [NestJS CLI](https://github.com/nestjs/nest-cli) has the ability to search in all of our code and create the [Swagger](https://swagger.io/) documentation automatically. To do so, the only thing that we need to modify is the *nest-cli.json* file adding the following lines:

```json
{
  ...
  "compilerOptions": {
    "plugins": ["@nestjs/swagger/plugin"]
  }
}
```

Once added, we can run the service again `npm run start:dev` but in this case, we are going to see the following error:

![](http://blog.yggdrasilts.com/content/images/2020/01/image-11.png)

This is because the service is using the *EchartOption* and the [NestJS Swagger plugin](https://docs.nestjs.com/recipes/swagger#plugin) is not able to parse. Also easy to solve. I am going to document this particular object by myself adding the following [NestJS Swagger decorators](https://docs.nestjs.com/recipes/swagger#decorators) to the *echartOptions* variable inside the `src/echarts/entities/options.entity.ts` file:

```typescript
import { ApiProperty } from '@nestjs/swagger';

import { EChartOption } from 'echarts';

import { ImageOptions } from './image-options.entity';

/**
 * Class to configure echarts options.
 */
export class Options {
  @ApiProperty({
    type: 'EChartOption',
    description: 'Chart configuration.',
    externalDocs: { url: 'https://echarts.apache.org/en/option.html' },
  })
  echartOptions: EChartOption;

  options?: ImageOptions;
}
```

Now, we can run the service again `npm run start:dev` and the Swagger documentation will have changed and we will have the new properties:

![](http://blog.yggdrasilts.com/content/images/2020/01/image-12.png)

> *As I said before, don't you think this is so easy?*

> *End of Part 4. You can check the project code in the [part-4](https://github.com/yggdrasilts/echarts-api-service/tree/part-4) tag*

## To Sum Up <a name="to-sum-up"></a>

As I said at the begging of this post, I am in love with [NestJS](https://nestjs.com/) because it is an awesome framework that helps you to create backend services in an efficient, reliable and scalable way, using [TypeScript](https://www.typescriptlang.org/), with which I am in love as well. In this post, it has been shown several parts of [NestJS](https://nestjs.com/) framework and how it helps you to build a backend service easily.

I hope you have enjoyed reading it and learn, improve or discover this great framework. In the following link, I leave you the Github repository where you can find the project code.

{% github yggdrasilts/echarts-api-service %}

Enjoy!!