How to convert class to Swagger Schema in NodeJS application - Documentation with Swagger in NodeJS become easier than ever

chabuuuu

chabuuuu

Posted on August 8, 2024

How to convert class to Swagger Schema in NodeJS application - Documentation with Swagger in NodeJS become easier than ever

Example that I have a DTO class that describe request body
for resgiter new user, I want to inject this class to the swagger schema

class RegisterUserRequestDto {
username!: string;

password!: string;
}
Enter fullscreen mode Exit fullscreen mode

Here I will use the npm package: class-to-swagger-schema

npm i class-to-swagger-schema
Enter fullscreen mode Exit fullscreen mode

The full gihub repo of this post is here: https://github.com/chabuuuu/class-to-swagger-schema/tree/main/example

First, I need to create a base schema for all request body to reuse it

//request-body-schema.ts

export const requestBodySchema = {
  type: "object",
  properties: {
    /**
     ** Add this if you want to inject your class here
     */
    injectClassHere: true,
  },
};
Enter fullscreen mode Exit fullscreen mode

The base schema will have the same format of general Swagger schema in Json type.

In the example above, we add to anywhere we want to inject the Typescript class to it

In this example, the package will inject the RegisterUserRequestDto to it, the result when convert to Swagger Schema will look like this:

    components:
      schemas:
        type: "object",
            properties:
                username:
                    type: "string"
                    description: "Username of user"
                    example: "my_username_is_cool_123"
                password:
                    type: "string"
                    description: "Password of user"
                    example: "my_password_is_cool_123"
Enter fullscreen mode Exit fullscreen mode

But you dont need to worry about the swagger yaml format anymore, let check below

import {
  SwaggerExample,
  SwaggerProperty,
  swaggerSchemaGenerator,
} from "class-to-swagger-schema";

const testRequestBody = swaggerSchemaGenerator.generateRequestBody(RegisterUserRequestDto);

Enter fullscreen mode Exit fullscreen mode

The above will auto generate the swagger schema for you

Then you just need to map it to your swagger schema define as below

export const swaggerSchemaMapping = {

RegisterRequestBodyDto: testRequestBody,

};
Enter fullscreen mode Exit fullscreen mode

//Finally, you can use the swaggerSchemaMapping to inject to the swagger schema in swagger option:

const options = {
  definition: {
    openapi: "3.1.0",
    info: {
      title: "ExpressJS Super Clean Base Source API Documentation",
      version: "0.1.0",
      description:
        "This is API application made with Express and documented with Swagger",
      license: {
        name: "MIT",
        url: "https://spdx.org/licenses/MIT.html",
      },
      contact: {
        name: "Thinh Ha",
        email: "haphuthinh332004@gmail.com",
      },
    },
    servers: [],
    components: {
      schemas: swaggerSchemaMapping, //Inject the schema mapping here
    },
  },
  apis: ["./controllers/*.ts"],
};
Enter fullscreen mode Exit fullscreen mode

Then, you just need to use the mapped schema normally using normal package swagger-ui-express:

export class UserController {
  /**
   * @openapi
   * /user/register:
   *   post:
   *     tags:
   *       - user
   *     summary: Register new user account
   *     description: Register new user account
   *     requestBody:
   *       required: true
   *       content:
   *         application/json:
   *           schema:
   *             $ref: '#/components/schemas/RegisterRequestBodyDto'
   */
  async registerUser(req: any, res: any, next: any) {}
}
Enter fullscreen mode Exit fullscreen mode

The result will as below:

image

Class property decorator

@SwaggerProperty

This will define that the folow property in class that have this decorator will be show in Swagger schema

Usage:

class TestDto {

    @SwaggerProperty("The id of user") //This will add the description for the property when convert to swagger schema
    id!: string

    @SwaggerProperty()
    password!: string
}
Enter fullscreen mode Exit fullscreen mode

@SwaggerExample

This will generate example for the folow property in swagger schema

class TestDto {

    @SwaggerProperty()
    @SwaggerExample("my_password") //This will show example as "my_password" in Swagger schema
    password!: string
}
Enter fullscreen mode Exit fullscreen mode

Schema configure

Style A

swaggerSchemaGenerator.configure({
  createSuccessResponseSchema: createSuccessResponseSchema,
  deleteSuccessResponseSchema: deleteSuccessResponseSchema,
  errorResponseSchema: errorResponseSchema,
  findManyPagingResponseSchema: findManyPagingResponseSchema,
  findManyResponseSchema: findManyResponseSchema,
  findOneResponseSchema: findOneResponseSchema,
  requestBodySchema: requestBodySchema,
  updateSuccessResponseSchema: updateSuccessResponseSchema,
});
Enter fullscreen mode Exit fullscreen mode

Style B

swaggerSchemaGenerator.setCreateSuccessResponseSchema(
  createSuccessResponseSchema
);
swaggerSchemaGenerator.setDeleteSuccessResponseSchema(
  deleteSuccessResponseSchema
);
swaggerSchemaGenerator.setErrorResponseSchema(errorResponseSchema);
swaggerSchemaGenerator.setFindManyPagingResponseSchema(
  findManyPagingResponseSchema
);
swaggerSchemaGenerator.setFindManyResponseSchema(findManyResponseSchema);
swaggerSchemaGenerator.setFindOneResponseSchema(findOneResponseSchema);
swaggerSchemaGenerator.setRequestBodySchema(requestBodySchema);
swaggerSchemaGenerator.setUpdateSuccessResponseSchema(
  updateSuccessResponseSchema
);
Enter fullscreen mode Exit fullscreen mode

Inject property

injectClassHere

This mark that the object that this will be replace with the class you inject:

export const requestBodySchema = {
  type: "object",
  properties: {
    /**
     ** Add this if you want to inject your class here
     */
    injectClassHere: true,
  },
};

Enter fullscreen mode Exit fullscreen mode

Then do this:

swaggerSchemaGenerator.setRequestBodySchema(requestBodySchema);

const testRequestBody = swaggerSchemaGenerator.generateRequestBody(
  RegisterUserRequestDto
);

/*
 value of testRequestBody =
    components:
      schemas:
        type: "object",
            properties:
                username:
                    type: "string"
                    description: "Username of user"
                    example: "my_username_is_cool_123"
                password:
                    type: "string"
                    description: "Password of user"
                    example: "my_password_is_cool_123"
*/
Enter fullscreen mode Exit fullscreen mode

injectHttpStatusExample

This mark that the object that this will be replace with the class you inject:

export const errorSchema = {
  type: "object",
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: {
        /**
         ** Add this if you want to inject http status example here
         */
        injectHttpStatusExample: true,
      },
    },
};

Enter fullscreen mode Exit fullscreen mode

Then do this:

swaggerSchemaGenerator.setErrorResponseSchema(errorSchema);


const testError = swaggerSchemaGenerator.generateErrorResponse(
  "",
  null,
  400, //The status code you want to inject
  null,
);

As a result, this will inject the status code: 400 to the

/*
 value of testError =
    components:
      schemas:
        type: "object",
            properties:
                httpStatus:
                    type: "integer"
                    description: "HTTP status code"
                    example: "400"
*/
Enter fullscreen mode Exit fullscreen mode

injectHttpMessageExample

This mark that the object that this will be replace with the class you inject:

export const errorSchema = {
  type: "object",
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: {
        /**
         ** Add this if you want to inject http message example here
         */
        injectHttpMessageExample: true,
      },
    },
};

Enter fullscreen mode Exit fullscreen mode

Then do this:

swaggerSchemaGenerator.setErrorResponseSchema(errorSchema);


const testError = swaggerSchemaGenerator.generateErrorResponse(
  "",
  null,
  null,
  "Bad request", //The status message you want to inject (optional)
);

As a result, this will inject the http message: "Bad request" to the

/*
 value of testError =
    components:
      schemas:
        type: "object",
            properties:
                httpMessage:
                    type: "string"
                    description: "HTTP status message"
                    example: ""Bad request""
*/
Enter fullscreen mode Exit fullscreen mode

Other schema type (totally 8 schema type)

Create success response schema

First init create success response schema:

export const createSuccessResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "201",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "Created",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "object",
      description: "Data response",
      properties: {
        /**
         ** Add this if you want to inject your class here
         */
        injectClassHere: true,
      },
    },
  },
};

swaggerSchemaGenerator.setCreateSuccessResponseSchema(
  createSuccessResponseSchema
);
Enter fullscreen mode Exit fullscreen mode

I have a DTO class that describe the response when register new user successfully:

class RegisterUserResponseDto {
@SwaggerProperty("Id of user")
@SwaggerExample("1562")
id!: number;

@SwaggerProperty("Username of user")
@SwaggerExample("my_user_name_is_cool_123")
username!: string;
}
Enter fullscreen mode Exit fullscreen mode

Finally, convert the dto to schema:

const testCreate = swaggerSchemaGenerator.generateCreateSuccessResponse(
RegisterUserResponseDto
);
Enter fullscreen mode Exit fullscreen mode

The result will as below:

image

Error schema

First, we need to create a base error schema

export const errorResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: {
        /**
         ** Add this if you want to inject http status example here
         */
        injectHttpStatusExample: true,
      },
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: {
        /**
         ** Add this if you want to inject http message example here
         */
        injectHttpMessageExample: true,
      },
    },
    error: {
      type: "object",
      description: "Error response",
      properties: {
        /**
         ** Add this if you want to inject your class here
         */
        injectClassHere: true,
      },
    },
    data: {
      type: "object",
      description: "Data response",
      example: null,
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

Example that I want to generate schema for the error response when register new user:
User provide invalid password, http status code is 400,
custom error code is INVALID_PASSWORD_ERROR, I want to inject this error to the swagger schema

const testError = swaggerSchemaGenerator.generateErrorResponse({
  message: "Your password must be at least 10 charactors", //The error message you want to inject (required)
  code: "INVALID_PASSWORD_ERROR", //The error code you want to inject (optional)
  httpStatusCode: 400, //The status code you want to inject (optional)
  httpStatusMessage: "Bad request", //The status message you want to inject (optional)
});
Enter fullscreen mode Exit fullscreen mode

Next, I need to mapping the schema above to the swagger schema

export const swaggerSchemaMapping = {
  /**
   ** POST /user/register
   */
  RegisterRequestBodyDto: testRequestBody,
  RegisterSuccessResponseDto: testCreate,
  Register_INVALID_PASSWORD_ERROR: testError,
};
Enter fullscreen mode Exit fullscreen mode

The result will as below:
image

Update success response schema

Example that I want to generate schema for the update success response

Create base update success response:

export const updateSuccessResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "200",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "OK",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "object",
      description: "Data response",
      properties: {
        message: {
          type: "string",
          description: "Message",
          example: "Updated successfully",
        },
      },
    },
  },
};


swaggerSchemaGenerator.setUpdateSuccessResponseSchema(
  updateSuccessResponseSchema
);
Enter fullscreen mode Exit fullscreen mode

Next, convert and mapping

const testUpdate = swaggerSchemaGenerator.generateUpdateSuccessResponse();
Enter fullscreen mode Exit fullscreen mode

Delete success response

Example that I want to generate schema for the delete success response

First, create delete success base schema:

export const deleteSuccessResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "200",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "OK",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "object",
      description: "Data response",
      properties: {
        message: {
          type: "string",
          description: "Message",
          example: "Deleted successfully",
        },
      },
    },
  },
};

swaggerSchemaGenerator.setDeleteSuccessResponseSchema(
  deleteSuccessResponseSchema
);
Enter fullscreen mode Exit fullscreen mode
const testDelete = swaggerSchemaGenerator.generateDeleteSuccessResponse();

Enter fullscreen mode Exit fullscreen mode

Find one response schema

Example that I want to generate schema for the find one response

First, create base find one success response schema:

export const findOneResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "200",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "OK",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "object",
      description: "Data response",
      properties: {
        /**
         ** Add this if you want to inject your class here
         */
        injectClassHere: true,
      },
    },
  },
};

swaggerSchemaGenerator.setFindOneResponseSchema(findOneResponseSchema);
Enter fullscreen mode Exit fullscreen mode

Convert as folow:

class ExampleDto {
@SwaggerProperty()
example!: string;
}

const testFindOne = swaggerSchemaGenerator.generateFindOneResponse(ExampleDto);
Enter fullscreen mode Exit fullscreen mode

Find many response schema

Example that I want to generate schema for the find many response

Create base find many response schema:

export const findManyResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "200",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "OK",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "array",
      description: "Data response",
      items: {
        type: "object",
        properties: {
          /**
           ** Add this if you want to inject your class here
           */
          injectClassHere: true,
        },
      },
    },
  },
};

swaggerSchemaGenerator.setFindManyResponseSchema(findManyResponseSchema);
Enter fullscreen mode Exit fullscreen mode

Convert as below:

class ExampleDto {
@SwaggerProperty()
example!: string;
}

const testFindMany =
swaggerSchemaGenerator.generateFindManyResponse(ExampleDto);
Enter fullscreen mode Exit fullscreen mode

Find many (with paging) response schema

Example that I want to generate schema for the find many paging response

First create find many (with paging) response schema:

export const findManyPagingResponseSchema = {
  type: "object",
  properties: {
    httpStatus: {
      type: "integer",
      description: "HTTP status code",
      example: "200",
    },
    httpMessage: {
      type: "string",
      description: "HTTP status message",
      example: "OK",
    },
    error: {
      type: "object",
      description: "Error response",
      example: null,
    },
    data: {
      type: "object",
      description: "Paging response",
      properties: {
        records: {
          type: "integer",
          description: "Total records",
          example: 20,
        },
        items: {
          type: "array",
          description: "Item response",
          items: {
            type: "object",
            properties: {
              /**
               ** Add this if you want to inject your class here
               */
              injectClassHere: true,
            },
          },
        },
        pages: {
          type: "integer",
          description: "Total pages",
          example: 2,
        },
        page: {
          type: "integer",
          description: "Current page",
          example: 1,
        },
        recordFrom: {
          type: "integer",
          description: "Record from",
          example: 1,
        },
        recordTo: {
          type: "integer",
          description: "Record to",
          example: 10,
        },
      },
    },
  },
};

swaggerSchemaGenerator.setFindManyPagingResponseSchema(
  findManyPagingResponseSchema
);
Enter fullscreen mode Exit fullscreen mode

Convert as below:

class ExampleDto {
@SwaggerProperty()
example!: string;
}

const testFindManyPaging =
swaggerSchemaGenerator.generateFindManyPagingResponse(ExampleDto);
Enter fullscreen mode Exit fullscreen mode
đź’– đź’Ş đź™… đźš©
chabuuuu
chabuuuu

Posted on August 8, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related