How to convert class to Swagger Schema in NodeJS application - Documentation with Swagger in NodeJS become easier than ever
chabuuuu
Posted on August 8, 2024
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;
}
Here I will use the npm package: class-to-swagger-schema
npm i class-to-swagger-schema
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,
},
};
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"
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);
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,
};
//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"],
};
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) {}
}
The result will as below:
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
}
@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
}
Schema configure
Style A
swaggerSchemaGenerator.configure({
createSuccessResponseSchema: createSuccessResponseSchema,
deleteSuccessResponseSchema: deleteSuccessResponseSchema,
errorResponseSchema: errorResponseSchema,
findManyPagingResponseSchema: findManyPagingResponseSchema,
findManyResponseSchema: findManyResponseSchema,
findOneResponseSchema: findOneResponseSchema,
requestBodySchema: requestBodySchema,
updateSuccessResponseSchema: updateSuccessResponseSchema,
});
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
);
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,
},
};
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"
*/
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,
},
},
};
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"
*/
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,
},
},
};
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""
*/
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
);
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;
}
Finally, convert the dto to schema:
const testCreate = swaggerSchemaGenerator.generateCreateSuccessResponse(
RegisterUserResponseDto
);
The result will as below:
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,
},
},
};
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)
});
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,
};
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
);
Next, convert and mapping
const testUpdate = swaggerSchemaGenerator.generateUpdateSuccessResponse();
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
);
const testDelete = swaggerSchemaGenerator.generateDeleteSuccessResponse();
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);
Convert as folow:
class ExampleDto {
@SwaggerProperty()
example!: string;
}
const testFindOne = swaggerSchemaGenerator.generateFindOneResponse(ExampleDto);
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);
Convert as below:
class ExampleDto {
@SwaggerProperty()
example!: string;
}
const testFindMany =
swaggerSchemaGenerator.generateFindManyResponse(ExampleDto);
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
);
Convert as below:
class ExampleDto {
@SwaggerProperty()
example!: string;
}
const testFindManyPaging =
swaggerSchemaGenerator.generateFindManyPagingResponse(ExampleDto);
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
November 29, 2024