From 0071202a90e9071eeb217326fefec4eccab85550 Mon Sep 17 00:00:00 2001 From: Vladyslav Shchepotin Date: Sat, 27 Apr 2024 19:51:42 +0300 Subject: [PATCH] feat(swagger): add DTOs to responses #1504 --- .install-scripts/scripts/remove-mongodb.ts | 52 ++++++++++++++++++- .install-scripts/scripts/remove-postgresql.ts | 51 ++++++++++++++++++ src/auth-apple/auth-apple.controller.ts | 9 ++-- src/auth-facebook/auth-facebook.controller.ts | 9 ++-- src/auth-google/auth-google.controller.ts | 11 ++-- src/auth-twitter/auth-twitter.controller.ts | 9 ++-- src/auth/auth.controller.ts | 23 +++++--- src/auth/auth.service.ts | 8 +-- src/auth/dto/auth-email-login.dto.ts | 2 +- src/auth/dto/auth-forgot-password.dto.ts | 2 +- src/auth/dto/auth-register-login.dto.ts | 2 +- src/auth/dto/login-response.dto.ts | 18 +++++++ src/auth/dto/refresh-response.dto.ts | 12 +++++ src/auth/types/login-response.type.ts | 8 --- src/files/config/file-config.type.ts | 1 - src/files/config/file.config.ts | 7 --- src/files/domain/file.ts | 11 +++- .../document/entities/file.schema.ts | 5 ++ .../relational/entities/file.entity.ts | 9 ++++ .../uploader/local/dto/file-response.dto.ts | 9 ++++ .../uploader/local/files.controller.ts | 9 +++- .../s3-presigned/dto/file-response.dto.ts | 14 +++++ .../uploader/s3-presigned/files.controller.ts | 6 ++- .../uploader/s3/dto/file-response.dto.ts | 9 ++++ .../uploader/s3/files.controller.ts | 16 +++++- src/roles/domain/role.ts | 16 ++++++ .../document/entities/role.schema.ts | 9 ++++ .../relational/entities/role.entity.ts | 8 +++ src/statuses/domain/status.ts | 16 ++++++ .../document/entities/status.schema.ts | 9 ++++ .../relational/entities/status.entity.ts | 8 +++ src/users/domain/user.ts | 52 +++++++++++++++++++ src/users/dto/create-user.dto.ts | 6 +-- src/users/dto/update-user.dto.ts | 12 ++--- .../document/entities/user.schema.ts | 33 ++++++++++++ .../relational/entities/user.entity.ts | 36 +++++++++++++ src/users/users.controller.ts | 27 ++++++++-- src/utils/document-entity-helper.ts | 4 ++ .../dto/infinity-pagination-response.dto.ts | 27 ++++++++++ src/utils/infinity-pagination.ts | 4 +- .../types/infinity-pagination-result.type.ts | 4 -- 41 files changed, 515 insertions(+), 68 deletions(-) create mode 100644 src/auth/dto/login-response.dto.ts create mode 100644 src/auth/dto/refresh-response.dto.ts delete mode 100644 src/auth/types/login-response.type.ts create mode 100644 src/files/infrastructure/uploader/local/dto/file-response.dto.ts create mode 100644 src/files/infrastructure/uploader/s3-presigned/dto/file-response.dto.ts create mode 100644 src/files/infrastructure/uploader/s3/dto/file-response.dto.ts create mode 100644 src/utils/dto/infinity-pagination-response.dto.ts delete mode 100644 src/utils/types/infinity-pagination-result.type.ts diff --git a/.install-scripts/scripts/remove-mongodb.ts b/.install-scripts/scripts/remove-mongodb.ts index cbd068858..517e6d292 100644 --- a/.install-scripts/scripts/remove-mongodb.ts +++ b/.install-scripts/scripts/remove-mongodb.ts @@ -222,7 +222,6 @@ const removeMongoDb = async () => { }, ], }); - replace({ path: path.join(process.cwd(), 'src', 'users', 'users.module.ts'), actions: [ @@ -244,6 +243,57 @@ const removeMongoDb = async () => { }, ], }); + replace({ + path: path.join(process.cwd(), 'src', 'users', 'domain', 'user.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = Number;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); + replace({ + path: path.join(process.cwd(), 'src', 'statuses', 'domain', 'status.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = Number;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); + replace({ + path: path.join(process.cwd(), 'src', 'roles', 'domain', 'role.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = Number;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); replace({ path: path.join(process.cwd(), 'package.json'), actions: [ diff --git a/.install-scripts/scripts/remove-postgresql.ts b/.install-scripts/scripts/remove-postgresql.ts index 30a266de9..7835cb10e 100644 --- a/.install-scripts/scripts/remove-postgresql.ts +++ b/.install-scripts/scripts/remove-postgresql.ts @@ -239,6 +239,57 @@ const removePostgreSql = async () => { }, ], }); + replace({ + path: path.join(process.cwd(), 'src', 'users', 'domain', 'user.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = String;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); + replace({ + path: path.join(process.cwd(), 'src', 'statuses', 'domain', 'status.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = String;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); + replace({ + path: path.join(process.cwd(), 'src', 'roles', 'domain', 'role.ts'), + actions: [ + { + find: /\/\/ .*\/\/ <\/database-block>/gs, + replace: `const idType = String;`, + }, + { + find: /\s*import \{ DatabaseConfig \} from .*/g, + replace: '', + }, + { + find: /\s*import databaseConfig from .*/g, + replace: '', + }, + ], + }); replace({ path: path.join(process.cwd(), 'package.json'), actions: [ diff --git a/src/auth-apple/auth-apple.controller.ts b/src/auth-apple/auth-apple.controller.ts index cb1fe55f7..f021d5084 100644 --- a/src/auth-apple/auth-apple.controller.ts +++ b/src/auth-apple/auth-apple.controller.ts @@ -6,11 +6,11 @@ import { Post, SerializeOptions, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthService } from '../auth/auth.service'; import { AuthAppleService } from './auth-apple.service'; import { AuthAppleLoginDto } from './dto/auth-apple-login.dto'; -import { LoginResponseType } from '../auth/types/login-response.type'; +import { LoginResponseDto } from '../auth/dto/login-response.dto'; @ApiTags('Auth') @Controller({ @@ -23,12 +23,15 @@ export class AuthAppleController { private readonly authAppleService: AuthAppleService, ) {} + @ApiOkResponse({ + type: LoginResponseDto, + }) @SerializeOptions({ groups: ['me'], }) @Post('login') @HttpCode(HttpStatus.OK) - async login(@Body() loginDto: AuthAppleLoginDto): Promise { + async login(@Body() loginDto: AuthAppleLoginDto): Promise { const socialData = await this.authAppleService.getProfileByToken(loginDto); return this.authService.validateSocialLogin('apple', socialData); diff --git a/src/auth-facebook/auth-facebook.controller.ts b/src/auth-facebook/auth-facebook.controller.ts index ccda0ea44..2ca5400fe 100644 --- a/src/auth-facebook/auth-facebook.controller.ts +++ b/src/auth-facebook/auth-facebook.controller.ts @@ -6,11 +6,11 @@ import { Post, SerializeOptions, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthService } from '../auth/auth.service'; import { AuthFacebookService } from './auth-facebook.service'; import { AuthFacebookLoginDto } from './dto/auth-facebook-login.dto'; -import { LoginResponseType } from '../auth/types/login-response.type'; +import { LoginResponseDto } from '../auth/dto/login-response.dto'; @ApiTags('Auth') @Controller({ @@ -23,6 +23,9 @@ export class AuthFacebookController { private readonly authFacebookService: AuthFacebookService, ) {} + @ApiOkResponse({ + type: LoginResponseDto, + }) @SerializeOptions({ groups: ['me'], }) @@ -30,7 +33,7 @@ export class AuthFacebookController { @HttpCode(HttpStatus.OK) async login( @Body() loginDto: AuthFacebookLoginDto, - ): Promise { + ): Promise { const socialData = await this.authFacebookService.getProfileByToken(loginDto); diff --git a/src/auth-google/auth-google.controller.ts b/src/auth-google/auth-google.controller.ts index f070b4853..d55f4d532 100644 --- a/src/auth-google/auth-google.controller.ts +++ b/src/auth-google/auth-google.controller.ts @@ -6,11 +6,11 @@ import { Post, SerializeOptions, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthService } from '../auth/auth.service'; import { AuthGoogleService } from './auth-google.service'; import { AuthGoogleLoginDto } from './dto/auth-google-login.dto'; -import { LoginResponseType } from '../auth/types/login-response.type'; +import { LoginResponseDto } from '../auth/dto/login-response.dto'; @ApiTags('Auth') @Controller({ @@ -23,14 +23,15 @@ export class AuthGoogleController { private readonly authGoogleService: AuthGoogleService, ) {} + @ApiOkResponse({ + type: LoginResponseDto, + }) @SerializeOptions({ groups: ['me'], }) @Post('login') @HttpCode(HttpStatus.OK) - async login( - @Body() loginDto: AuthGoogleLoginDto, - ): Promise { + async login(@Body() loginDto: AuthGoogleLoginDto): Promise { const socialData = await this.authGoogleService.getProfileByToken(loginDto); return this.authService.validateSocialLogin('google', socialData); diff --git a/src/auth-twitter/auth-twitter.controller.ts b/src/auth-twitter/auth-twitter.controller.ts index dc4b39e98..b165f37ce 100644 --- a/src/auth-twitter/auth-twitter.controller.ts +++ b/src/auth-twitter/auth-twitter.controller.ts @@ -6,11 +6,11 @@ import { Post, SerializeOptions, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthService } from '../auth/auth.service'; import { AuthTwitterService } from './auth-twitter.service'; import { AuthTwitterLoginDto } from './dto/auth-twitter-login.dto'; -import { LoginResponseType } from '../auth/types/login-response.type'; +import { LoginResponseDto } from '../auth/dto/login-response.dto'; @ApiTags('Auth') @Controller({ @@ -23,6 +23,9 @@ export class AuthTwitterController { private readonly authTwitterService: AuthTwitterService, ) {} + @ApiOkResponse({ + type: LoginResponseDto, + }) @SerializeOptions({ groups: ['me'], }) @@ -30,7 +33,7 @@ export class AuthTwitterController { @HttpCode(HttpStatus.OK) async login( @Body() loginDto: AuthTwitterLoginDto, - ): Promise { + ): Promise { const socialData = await this.authTwitterService.getProfileByToken(loginDto); diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 8e33eba7e..dff88f7a2 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -12,7 +12,7 @@ import { SerializeOptions, } from '@nestjs/common'; import { AuthService } from './auth.service'; -import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthEmailLoginDto } from './dto/auth-email-login.dto'; import { AuthForgotPasswordDto } from './dto/auth-forgot-password.dto'; import { AuthConfirmEmailDto } from './dto/auth-confirm-email.dto'; @@ -20,9 +20,10 @@ import { AuthResetPasswordDto } from './dto/auth-reset-password.dto'; import { AuthUpdateDto } from './dto/auth-update.dto'; import { AuthGuard } from '@nestjs/passport'; import { AuthRegisterLoginDto } from './dto/auth-register-login.dto'; -import { LoginResponseType } from './types/login-response.type'; +import { LoginResponseDto } from './dto/login-response.dto'; import { NullableType } from '../utils/types/nullable.type'; import { User } from '../users/domain/user'; +import { RefreshResponseDto } from './dto/refresh-response.dto'; @ApiTags('Auth') @Controller({ @@ -36,10 +37,11 @@ export class AuthController { groups: ['me'], }) @Post('email/login') + @ApiOkResponse({ + type: LoginResponseDto, + }) @HttpCode(HttpStatus.OK) - public login( - @Body() loginDto: AuthEmailLoginDto, - ): Promise { + public login(@Body() loginDto: AuthEmailLoginDto): Promise { return this.service.validateLogin(loginDto); } @@ -88,19 +90,25 @@ export class AuthController { }) @Get('me') @UseGuards(AuthGuard('jwt')) + @ApiOkResponse({ + type: User, + }) @HttpCode(HttpStatus.OK) public me(@Request() request): Promise> { return this.service.me(request.user); } @ApiBearerAuth() + @ApiOkResponse({ + type: RefreshResponseDto, + }) @SerializeOptions({ groups: ['me'], }) @Post('refresh') @UseGuards(AuthGuard('jwt-refresh')) @HttpCode(HttpStatus.OK) - public refresh(@Request() request): Promise> { + public refresh(@Request() request): Promise { return this.service.refreshToken({ sessionId: request.user.sessionId, hash: request.user.hash, @@ -124,6 +132,9 @@ export class AuthController { @Patch('me') @UseGuards(AuthGuard('jwt')) @HttpCode(HttpStatus.OK) + @ApiOkResponse({ + type: User, + }) public update( @Request() request, @Body() userDto: AuthUpdateDto, diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 3ec787177..a75834b64 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -16,7 +16,7 @@ import { AuthProvidersEnum } from './auth-providers.enum'; import { SocialInterface } from '../social/interfaces/social.interface'; import { AuthRegisterLoginDto } from './dto/auth-register-login.dto'; import { NullableType } from '../utils/types/nullable.type'; -import { LoginResponseType } from './types/login-response.type'; +import { LoginResponseDto } from './dto/login-response.dto'; import { ConfigService } from '@nestjs/config'; import { JwtRefreshPayloadType } from './strategies/types/jwt-refresh-payload.type'; import { JwtPayloadType } from './strategies/types/jwt-payload.type'; @@ -39,7 +39,7 @@ export class AuthService { private configService: ConfigService, ) {} - async validateLogin(loginDto: AuthEmailLoginDto): Promise { + async validateLogin(loginDto: AuthEmailLoginDto): Promise { const user = await this.usersService.findOne({ email: loginDto.email, }); @@ -113,7 +113,7 @@ export class AuthService { async validateSocialLogin( authProvider: string, socialData: SocialInterface, - ): Promise { + ): Promise { let user: NullableType = null; const socialEmail = socialData.email?.toLowerCase(); let userByEmail: NullableType = null; @@ -520,7 +520,7 @@ export class AuthService { async refreshToken( data: Pick, - ): Promise> { + ): Promise> { const session = await this.sessionService.findOne({ id: data.sessionId, }); diff --git a/src/auth/dto/auth-email-login.dto.ts b/src/auth/dto/auth-email-login.dto.ts index ea27f1915..cb1a166e3 100644 --- a/src/auth/dto/auth-email-login.dto.ts +++ b/src/auth/dto/auth-email-login.dto.ts @@ -4,7 +4,7 @@ import { Transform } from 'class-transformer'; import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; export class AuthEmailLoginDto { - @ApiProperty({ example: 'test1@example.com' }) + @ApiProperty({ example: 'test1@example.com', type: String }) @Transform(lowerCaseTransformer) @IsEmail() @IsNotEmpty() diff --git a/src/auth/dto/auth-forgot-password.dto.ts b/src/auth/dto/auth-forgot-password.dto.ts index 0fd6b4a4f..2aac90194 100644 --- a/src/auth/dto/auth-forgot-password.dto.ts +++ b/src/auth/dto/auth-forgot-password.dto.ts @@ -4,7 +4,7 @@ import { Transform } from 'class-transformer'; import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; export class AuthForgotPasswordDto { - @ApiProperty() + @ApiProperty({ example: 'test1@example.com', type: String }) @Transform(lowerCaseTransformer) @IsEmail() email: string; diff --git a/src/auth/dto/auth-register-login.dto.ts b/src/auth/dto/auth-register-login.dto.ts index 06e57f9d6..0a88afdec 100644 --- a/src/auth/dto/auth-register-login.dto.ts +++ b/src/auth/dto/auth-register-login.dto.ts @@ -4,7 +4,7 @@ import { Transform } from 'class-transformer'; import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; export class AuthRegisterLoginDto { - @ApiProperty({ example: 'test1@example.com' }) + @ApiProperty({ example: 'test1@example.com', type: String }) @Transform(lowerCaseTransformer) @IsEmail() email: string; diff --git a/src/auth/dto/login-response.dto.ts b/src/auth/dto/login-response.dto.ts new file mode 100644 index 000000000..a48da6c92 --- /dev/null +++ b/src/auth/dto/login-response.dto.ts @@ -0,0 +1,18 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; +import { User } from '../../users/domain/user'; + +export class LoginResponseDto { + @ApiResponseProperty() + token: string; + + @ApiResponseProperty() + refreshToken: string; + + @ApiResponseProperty() + tokenExpires: number; + + @ApiResponseProperty({ + type: () => User, + }) + user: User; +} diff --git a/src/auth/dto/refresh-response.dto.ts b/src/auth/dto/refresh-response.dto.ts new file mode 100644 index 000000000..68229a615 --- /dev/null +++ b/src/auth/dto/refresh-response.dto.ts @@ -0,0 +1,12 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; + +export class RefreshResponseDto { + @ApiResponseProperty() + token: string; + + @ApiResponseProperty() + refreshToken: string; + + @ApiResponseProperty() + tokenExpires: number; +} diff --git a/src/auth/types/login-response.type.ts b/src/auth/types/login-response.type.ts deleted file mode 100644 index 061ee9493..000000000 --- a/src/auth/types/login-response.type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { User } from '../../users/domain/user'; - -export type LoginResponseType = Readonly<{ - token: string; - refreshToken: string; - tokenExpires: number; - user: User; -}>; diff --git a/src/files/config/file-config.type.ts b/src/files/config/file-config.type.ts index 24a68623a..c0b29c908 100644 --- a/src/files/config/file-config.type.ts +++ b/src/files/config/file-config.type.ts @@ -9,7 +9,6 @@ export type FileConfig = { accessKeyId?: string; secretAccessKey?: string; awsDefaultS3Bucket?: string; - awsDefaultS3Url?: string; awsS3Region?: string; maxFileSize: number; }; diff --git a/src/files/config/file.config.ts b/src/files/config/file.config.ts index 78dc6f128..422c3ab0d 100644 --- a/src/files/config/file.config.ts +++ b/src/files/config/file.config.ts @@ -26,12 +26,6 @@ class EnvironmentVariablesValidator { @IsString() AWS_DEFAULT_S3_BUCKET: string; - @ValidateIf((envValues) => - [FileDriver.S3, FileDriver.S3_PRESIGNED].includes(envValues.FILE_DRIVER), - ) - @IsString() - AWS_DEFAULT_S3_URL: string; - @ValidateIf((envValues) => [FileDriver.S3, FileDriver.S3_PRESIGNED].includes(envValues.FILE_DRIVER), ) @@ -48,7 +42,6 @@ export default registerAs('file', () => { accessKeyId: process.env.ACCESS_KEY_ID, secretAccessKey: process.env.SECRET_ACCESS_KEY, awsDefaultS3Bucket: process.env.AWS_DEFAULT_S3_BUCKET, - awsDefaultS3Url: process.env.AWS_DEFAULT_S3_URL, awsS3Region: process.env.AWS_S3_REGION, maxFileSize: 5242880, // 5mb }; diff --git a/src/files/domain/file.ts b/src/files/domain/file.ts index 2c97d6637..537bda1f2 100644 --- a/src/files/domain/file.ts +++ b/src/files/domain/file.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; import { Allow } from 'class-validator'; import { Transform } from 'class-transformer'; import fileConfig from '../config/file.config'; @@ -10,10 +10,17 @@ import { AppConfig } from '../../config/app-config.type'; import appConfig from '../../config/app.config'; export class FileType { - @ApiProperty({ example: 'cbcfa8b8-3a25-4adb-a9c6-e325f0d0f3ae' }) + @ApiProperty({ + type: String, + example: 'cbcfa8b8-3a25-4adb-a9c6-e325f0d0f3ae', + }) @Allow() id: string; + @ApiResponseProperty({ + type: String, + example: 'https://example.com/path/to/file.jpg', + }) @Transform( ({ value }) => { if ((fileConfig() as FileConfig).driver === FileDriver.LOCAL) { diff --git a/src/files/infrastructure/persistence/document/entities/file.schema.ts b/src/files/infrastructure/persistence/document/entities/file.schema.ts index d41570d3b..ea304b2d8 100644 --- a/src/files/infrastructure/persistence/document/entities/file.schema.ts +++ b/src/files/infrastructure/persistence/document/entities/file.schema.ts @@ -11,6 +11,7 @@ import appConfig from '../../../../../config/app.config'; import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; import { FileConfig, FileDriver } from '../../../../config/file-config.type'; import fileConfig from '../../../../config/file.config'; +import { ApiResponseProperty } from '@nestjs/swagger'; export type FileSchemaDocument = HydratedDocument; @@ -21,6 +22,10 @@ export type FileSchemaDocument = HydratedDocument; }, }) export class FileSchemaClass extends EntityDocumentHelper { + @ApiResponseProperty({ + type: String, + example: 'https://example.com/path/to/file.jpg', + }) @Prop() @Transform( ({ value }) => { diff --git a/src/files/infrastructure/persistence/relational/entities/file.entity.ts b/src/files/infrastructure/persistence/relational/entities/file.entity.ts index be3a1f694..ad60d3001 100644 --- a/src/files/infrastructure/persistence/relational/entities/file.entity.ts +++ b/src/files/infrastructure/persistence/relational/entities/file.entity.ts @@ -10,12 +10,21 @@ import appConfig from '../../../../../config/app.config'; import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; import { FileConfig, FileDriver } from '../../../../config/file-config.type'; import fileConfig from '../../../../config/file.config'; +import { ApiResponseProperty } from '@nestjs/swagger'; @Entity({ name: 'file' }) export class FileEntity extends EntityRelationalHelper { + @ApiResponseProperty({ + type: String, + example: 'cbcfa8b8-3a25-4adb-a9c6-e325f0d0f3ae', + }) @PrimaryGeneratedColumn('uuid') id: string; + @ApiResponseProperty({ + type: String, + example: 'https://example.com/path/to/file.jpg', + }) @Column() @Transform( ({ value }) => { diff --git a/src/files/infrastructure/uploader/local/dto/file-response.dto.ts b/src/files/infrastructure/uploader/local/dto/file-response.dto.ts new file mode 100644 index 000000000..2aac4dde2 --- /dev/null +++ b/src/files/infrastructure/uploader/local/dto/file-response.dto.ts @@ -0,0 +1,9 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; +import { FileType } from '../../../../domain/file'; + +export class FileResponseDto { + @ApiResponseProperty({ + type: () => FileType, + }) + file: FileType; +} diff --git a/src/files/infrastructure/uploader/local/files.controller.ts b/src/files/infrastructure/uploader/local/files.controller.ts index 934d219df..e300ba77c 100644 --- a/src/files/infrastructure/uploader/local/files.controller.ts +++ b/src/files/infrastructure/uploader/local/files.controller.ts @@ -13,11 +13,13 @@ import { ApiBearerAuth, ApiBody, ApiConsumes, + ApiOkResponse, ApiParam, ApiTags, } from '@nestjs/swagger'; import { AuthGuard } from '@nestjs/passport'; import { FilesLocalService } from './files.service'; +import { FileResponseDto } from './dto/file-response.dto'; @ApiTags('Files') @Controller({ @@ -27,6 +29,9 @@ import { FilesLocalService } from './files.service'; export class FilesLocalController { constructor(private readonly filesService: FilesLocalService) {} + @ApiOkResponse({ + type: FileResponseDto, + }) @ApiBearerAuth() @UseGuards(AuthGuard('jwt')) @Post('upload') @@ -43,7 +48,9 @@ export class FilesLocalController { }, }) @UseInterceptors(FileInterceptor('file')) - async uploadFile(@UploadedFile() file: Express.Multer.File) { + async uploadFile( + @UploadedFile() file: Express.Multer.File, + ): Promise { return this.filesService.create(file); } diff --git a/src/files/infrastructure/uploader/s3-presigned/dto/file-response.dto.ts b/src/files/infrastructure/uploader/s3-presigned/dto/file-response.dto.ts new file mode 100644 index 000000000..e4309df84 --- /dev/null +++ b/src/files/infrastructure/uploader/s3-presigned/dto/file-response.dto.ts @@ -0,0 +1,14 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; +import { FileType } from '../../../../domain/file'; + +export class FileResponseDto { + @ApiResponseProperty({ + type: () => FileType, + }) + file: FileType; + + @ApiResponseProperty({ + type: String, + }) + uploadSignedUrl: string; +} diff --git a/src/files/infrastructure/uploader/s3-presigned/files.controller.ts b/src/files/infrastructure/uploader/s3-presigned/files.controller.ts index 700bf86d0..d94feee66 100644 --- a/src/files/infrastructure/uploader/s3-presigned/files.controller.ts +++ b/src/files/infrastructure/uploader/s3-presigned/files.controller.ts @@ -1,8 +1,9 @@ import { Body, Controller, Post, UseGuards } from '@nestjs/common'; -import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { AuthGuard } from '@nestjs/passport'; import { FilesS3PresignedService } from './files.service'; import { FileUploadDto } from './dto/file.dto'; +import { FileResponseDto } from './dto/file-response.dto'; @ApiTags('Files') @Controller({ @@ -12,6 +13,9 @@ import { FileUploadDto } from './dto/file.dto'; export class FilesS3PresignedController { constructor(private readonly filesService: FilesS3PresignedService) {} + @ApiOkResponse({ + type: FileResponseDto, + }) @ApiBearerAuth() @UseGuards(AuthGuard('jwt')) @Post('upload') diff --git a/src/files/infrastructure/uploader/s3/dto/file-response.dto.ts b/src/files/infrastructure/uploader/s3/dto/file-response.dto.ts new file mode 100644 index 000000000..2aac4dde2 --- /dev/null +++ b/src/files/infrastructure/uploader/s3/dto/file-response.dto.ts @@ -0,0 +1,9 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; +import { FileType } from '../../../../domain/file'; + +export class FileResponseDto { + @ApiResponseProperty({ + type: () => FileType, + }) + file: FileType; +} diff --git a/src/files/infrastructure/uploader/s3/files.controller.ts b/src/files/infrastructure/uploader/s3/files.controller.ts index 42f381c2b..1768538ff 100644 --- a/src/files/infrastructure/uploader/s3/files.controller.ts +++ b/src/files/infrastructure/uploader/s3/files.controller.ts @@ -6,9 +6,16 @@ import { UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; -import { ApiBearerAuth, ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiBody, + ApiConsumes, + ApiOkResponse, + ApiTags, +} from '@nestjs/swagger'; import { AuthGuard } from '@nestjs/passport'; import { FilesS3Service } from './files.service'; +import { FileResponseDto } from './dto/file-response.dto'; @ApiTags('Files') @Controller({ @@ -18,6 +25,9 @@ import { FilesS3Service } from './files.service'; export class FilesS3Controller { constructor(private readonly filesService: FilesS3Service) {} + @ApiOkResponse({ + type: FileResponseDto, + }) @ApiBearerAuth() @UseGuards(AuthGuard('jwt')) @Post('upload') @@ -34,7 +44,9 @@ export class FilesS3Controller { }, }) @UseInterceptors(FileInterceptor('file')) - async uploadFile(@UploadedFile() file: Express.MulterS3.File) { + async uploadFile( + @UploadedFile() file: Express.MulterS3.File, + ): Promise { return this.filesService.create(file); } } diff --git a/src/roles/domain/role.ts b/src/roles/domain/role.ts index a5feefedd..1270c6f38 100644 --- a/src/roles/domain/role.ts +++ b/src/roles/domain/role.ts @@ -1,9 +1,25 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; import { Allow } from 'class-validator'; +import databaseConfig from '../../database/config/database.config'; +import { DatabaseConfig } from '../../database/config/database-config.type'; + +// +const idType = (databaseConfig() as DatabaseConfig).isDocumentDatabase + ? String + : Number; +// export class Role { @Allow() + @ApiResponseProperty({ + type: idType, + }) id: number | string; @Allow() + @ApiResponseProperty({ + type: String, + example: 'admin', + }) name?: string; } diff --git a/src/roles/infrastructure/persistence/document/entities/role.schema.ts b/src/roles/infrastructure/persistence/document/entities/role.schema.ts index a529a79fb..6d8055b93 100644 --- a/src/roles/infrastructure/persistence/document/entities/role.schema.ts +++ b/src/roles/infrastructure/persistence/document/entities/role.schema.ts @@ -1,5 +1,14 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; + export class RoleSchema { + @ApiResponseProperty({ + type: String, + }) _id: string; + @ApiResponseProperty({ + type: String, + example: 'admin', + }) name?: string; } diff --git a/src/roles/infrastructure/persistence/relational/entities/role.entity.ts b/src/roles/infrastructure/persistence/relational/entities/role.entity.ts index 5e398b701..5aba62d42 100644 --- a/src/roles/infrastructure/persistence/relational/entities/role.entity.ts +++ b/src/roles/infrastructure/persistence/relational/entities/role.entity.ts @@ -1,13 +1,21 @@ import { Column, Entity, PrimaryColumn } from 'typeorm'; import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; +import { ApiResponseProperty } from '@nestjs/swagger'; @Entity({ name: 'role', }) export class RoleEntity extends EntityRelationalHelper { + @ApiResponseProperty({ + type: Number, + }) @PrimaryColumn() id: number; + @ApiResponseProperty({ + type: String, + example: 'admin', + }) @Column() name?: string; } diff --git a/src/statuses/domain/status.ts b/src/statuses/domain/status.ts index c68d65b85..5625aba90 100644 --- a/src/statuses/domain/status.ts +++ b/src/statuses/domain/status.ts @@ -1,9 +1,25 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; import { Allow } from 'class-validator'; +import databaseConfig from '../../database/config/database.config'; +import { DatabaseConfig } from '../../database/config/database-config.type'; + +// +const idType = (databaseConfig() as DatabaseConfig).isDocumentDatabase + ? String + : Number; +// export class Status { @Allow() + @ApiResponseProperty({ + type: idType, + }) id: number | string; @Allow() + @ApiResponseProperty({ + type: String, + example: 'active', + }) name?: string; } diff --git a/src/statuses/infrastructure/persistence/document/entities/status.schema.ts b/src/statuses/infrastructure/persistence/document/entities/status.schema.ts index f98c2c971..34ffdc558 100644 --- a/src/statuses/infrastructure/persistence/document/entities/status.schema.ts +++ b/src/statuses/infrastructure/persistence/document/entities/status.schema.ts @@ -1,5 +1,14 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; + export class StatusSchema { + @ApiResponseProperty({ + type: String, + }) _id: string; + @ApiResponseProperty({ + type: String, + example: 'active', + }) name?: string; } diff --git a/src/statuses/infrastructure/persistence/relational/entities/status.entity.ts b/src/statuses/infrastructure/persistence/relational/entities/status.entity.ts index dd14fb5f2..cfd3efdb0 100644 --- a/src/statuses/infrastructure/persistence/relational/entities/status.entity.ts +++ b/src/statuses/infrastructure/persistence/relational/entities/status.entity.ts @@ -2,14 +2,22 @@ import { Column, Entity, PrimaryColumn } from 'typeorm'; import { Status } from '../../../../domain/status'; import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; +import { ApiResponseProperty } from '@nestjs/swagger'; @Entity({ name: 'status', }) export class StatusEntity extends EntityRelationalHelper implements Status { + @ApiResponseProperty({ + type: Number, + }) @PrimaryColumn() id: number; + @ApiResponseProperty({ + type: String, + example: 'active', + }) @Column() name?: string; } diff --git a/src/users/domain/user.ts b/src/users/domain/user.ts index ad8d24f1e..f5a92adf8 100644 --- a/src/users/domain/user.ts +++ b/src/users/domain/user.ts @@ -2,10 +2,26 @@ import { Exclude, Expose } from 'class-transformer'; import { FileType } from '../../files/domain/file'; import { Role } from '../../roles/domain/role'; import { Status } from '../../statuses/domain/status'; +import { ApiResponseProperty } from '@nestjs/swagger'; +import databaseConfig from '../../database/config/database.config'; +import { DatabaseConfig } from '../../database/config/database-config.type'; + +// +const idType = (databaseConfig() as DatabaseConfig).isDocumentDatabase + ? String + : Number; +// export class User { + @ApiResponseProperty({ + type: idType, + }) id: number | string; + @ApiResponseProperty({ + type: String, + example: 'john.doe@example.com', + }) @Expose({ groups: ['me', 'admin'] }) email: string | null; @@ -15,17 +31,53 @@ export class User { @Exclude({ toPlainOnly: true }) previousPassword?: string; + @ApiResponseProperty({ + type: String, + example: 'email', + }) @Expose({ groups: ['me', 'admin'] }) provider: string; + @ApiResponseProperty({ + type: String, + example: '1234567890', + }) @Expose({ groups: ['me', 'admin'] }) socialId?: string | null; + + @ApiResponseProperty({ + type: String, + example: 'John', + }) firstName: string | null; + + @ApiResponseProperty({ + type: String, + example: 'Doe', + }) lastName: string | null; + + @ApiResponseProperty({ + type: () => FileType, + }) photo?: FileType | null; + + @ApiResponseProperty({ + type: () => Role, + }) role?: Role | null; + + @ApiResponseProperty({ + type: () => Status, + }) status?: Status; + + @ApiResponseProperty() createdAt: Date; + + @ApiResponseProperty() updatedAt: Date; + + @ApiResponseProperty() deletedAt: Date; } diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts index 17ab4da14..736b93d30 100644 --- a/src/users/dto/create-user.dto.ts +++ b/src/users/dto/create-user.dto.ts @@ -7,7 +7,7 @@ import { StatusDto } from '../../statuses/dto/status.dto'; import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; export class CreateUserDto { - @ApiProperty({ example: 'test1@example.com' }) + @ApiProperty({ example: 'test1@example.com', type: String }) @Transform(lowerCaseTransformer) @IsNotEmpty() @IsEmail() @@ -21,11 +21,11 @@ export class CreateUserDto { socialId?: string | null; - @ApiProperty({ example: 'John' }) + @ApiProperty({ example: 'John', type: String }) @IsNotEmpty() firstName: string | null; - @ApiProperty({ example: 'Doe' }) + @ApiProperty({ example: 'Doe', type: String }) @IsNotEmpty() lastName: string | null; diff --git a/src/users/dto/update-user.dto.ts b/src/users/dto/update-user.dto.ts index cc235cd04..c16933c1c 100644 --- a/src/users/dto/update-user.dto.ts +++ b/src/users/dto/update-user.dto.ts @@ -9,7 +9,7 @@ import { StatusDto } from '../../statuses/dto/status.dto'; import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; export class UpdateUserDto extends PartialType(CreateUserDto) { - @ApiPropertyOptional({ example: 'test1@example.com' }) + @ApiPropertyOptional({ example: 'test1@example.com', type: String }) @Transform(lowerCaseTransformer) @IsOptional() @IsEmail() @@ -24,24 +24,24 @@ export class UpdateUserDto extends PartialType(CreateUserDto) { socialId?: string | null; - @ApiPropertyOptional({ example: 'John' }) + @ApiPropertyOptional({ example: 'John', type: String }) @IsOptional() firstName?: string | null; - @ApiPropertyOptional({ example: 'Doe' }) + @ApiPropertyOptional({ example: 'Doe', type: String }) @IsOptional() lastName?: string | null; - @ApiPropertyOptional({ type: FileDto }) + @ApiPropertyOptional({ type: () => FileDto }) @IsOptional() photo?: FileDto | null; - @ApiPropertyOptional({ type: RoleDto }) + @ApiPropertyOptional({ type: () => RoleDto }) @IsOptional() @Type(() => RoleDto) role?: RoleDto | null; - @ApiPropertyOptional({ type: StatusDto }) + @ApiPropertyOptional({ type: () => StatusDto }) @IsOptional() @Type(() => StatusDto) status?: StatusDto; diff --git a/src/users/infrastructure/persistence/document/entities/user.schema.ts b/src/users/infrastructure/persistence/document/entities/user.schema.ts index b4cc5449c..dae84731d 100644 --- a/src/users/infrastructure/persistence/document/entities/user.schema.ts +++ b/src/users/infrastructure/persistence/document/entities/user.schema.ts @@ -10,6 +10,7 @@ import { FileSchemaClass } from '../../../../../files/infrastructure/persistence import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; import { StatusSchema } from '../../../../../statuses/infrastructure/persistence/document/entities/status.schema'; import { RoleSchema } from '../../../../../roles/infrastructure/persistence/document/entities/role.schema'; +import { ApiResponseProperty } from '@nestjs/swagger'; export type UserSchemaDocument = HydratedDocument; @@ -21,6 +22,10 @@ export type UserSchemaDocument = HydratedDocument; }, }) export class UserSchemaClass extends EntityDocumentHelper { + @ApiResponseProperty({ + type: String, + example: 'john.doe@example.com', + }) @Prop({ type: String, unique: true, @@ -35,12 +40,20 @@ export class UserSchemaClass extends EntityDocumentHelper { @Exclude({ toPlainOnly: true }) previousPassword?: string; + @ApiResponseProperty({ + type: String, + example: 'email', + }) @Expose({ groups: ['me', 'admin'], toPlainOnly: true }) @Prop({ default: AuthProvidersEnum.email, }) provider: string; + @ApiResponseProperty({ + type: String, + example: '1234567890', + }) @Expose({ groups: ['me', 'admin'], toPlainOnly: true }) @Prop({ type: String, @@ -48,38 +61,58 @@ export class UserSchemaClass extends EntityDocumentHelper { }) socialId?: string | null; + @ApiResponseProperty({ + type: String, + example: 'John', + }) @Prop({ type: String, }) firstName: string | null; + @ApiResponseProperty({ + type: String, + example: 'Doe', + }) @Prop({ type: String, }) lastName: string | null; + @ApiResponseProperty({ + type: () => FileSchemaClass, + }) @Prop({ type: FileSchemaClass, }) @Type(() => FileSchemaClass) photo?: FileSchemaClass | null; + @ApiResponseProperty({ + type: () => RoleSchema, + }) @Prop({ type: RoleSchema, }) role?: RoleSchema | null; + @ApiResponseProperty({ + type: () => StatusSchema, + }) @Prop({ type: StatusSchema, }) status?: StatusSchema; + @ApiResponseProperty() @Prop({ default: now }) createdAt: Date; + @ApiResponseProperty() @Prop({ default: now }) updatedAt: Date; + @ApiResponseProperty() @Prop() deletedAt: Date; } diff --git a/src/users/infrastructure/persistence/relational/entities/user.entity.ts b/src/users/infrastructure/persistence/relational/entities/user.entity.ts index efb57cbd8..7e889d366 100644 --- a/src/users/infrastructure/persistence/relational/entities/user.entity.ts +++ b/src/users/infrastructure/persistence/relational/entities/user.entity.ts @@ -21,14 +21,22 @@ import { EntityRelationalHelper } from '../../../../../utils/relational-entity-h // We duplicate these rules because you can choose not to use adapters // in your project and return an ORM entity directly in response. import { Exclude, Expose } from 'class-transformer'; +import { ApiResponseProperty } from '@nestjs/swagger'; @Entity({ name: 'user', }) export class UserEntity extends EntityRelationalHelper implements User { + @ApiResponseProperty({ + type: Number, + }) @PrimaryGeneratedColumn() id: number; + @ApiResponseProperty({ + type: String, + example: 'john.doe@example.com', + }) // For "string | null" we need to use String type. // More info: https://github.com/typeorm/typeorm/issues/2567 @Column({ type: String, unique: true, nullable: true }) @@ -47,44 +55,72 @@ export class UserEntity extends EntityRelationalHelper implements User { this.previousPassword = this.password; } + @ApiResponseProperty({ + type: String, + example: 'email', + }) @Column({ default: AuthProvidersEnum.email }) @Expose({ groups: ['me', 'admin'] }) provider: string; + @ApiResponseProperty({ + type: String, + example: '1234567890', + }) @Index() @Column({ type: String, nullable: true }) @Expose({ groups: ['me', 'admin'] }) socialId?: string | null; + @ApiResponseProperty({ + type: String, + example: 'John', + }) @Index() @Column({ type: String, nullable: true }) firstName: string | null; + @ApiResponseProperty({ + type: String, + example: 'Doe', + }) @Index() @Column({ type: String, nullable: true }) lastName: string | null; + @ApiResponseProperty({ + type: () => FileEntity, + }) @ManyToOne(() => FileEntity, { eager: true, }) photo?: FileEntity | null; + @ApiResponseProperty({ + type: () => RoleEntity, + }) @ManyToOne(() => RoleEntity, { eager: true, }) role?: RoleEntity | null; + @ApiResponseProperty({ + type: () => StatusEntity, + }) @ManyToOne(() => StatusEntity, { eager: true, }) status?: StatusEntity; + @ApiResponseProperty() @CreateDateColumn() createdAt: Date; + @ApiResponseProperty() @UpdateDateColumn() updatedAt: Date; + @ApiResponseProperty() @DeleteDateColumn() deletedAt: Date; } diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index dbd41a747..90b32eede 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -14,12 +14,21 @@ import { } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; -import { ApiBearerAuth, ApiParam, ApiTags } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiCreatedResponse, + ApiOkResponse, + ApiParam, + ApiTags, +} from '@nestjs/swagger'; import { Roles } from '../roles/roles.decorator'; import { RoleEnum } from '../roles/roles.enum'; import { AuthGuard } from '@nestjs/passport'; -import { InfinityPaginationResultType } from '../utils/types/infinity-pagination-result.type'; +import { + InfinityPaginationResponse, + InfinityPaginationResponseDto, +} from '../utils/dto/infinity-pagination-response.dto'; import { NullableType } from '../utils/types/nullable.type'; import { QueryUserDto } from './dto/query-user.dto'; import { User } from './domain/user'; @@ -38,6 +47,9 @@ import { infinityPagination } from '../utils/infinity-pagination'; export class UsersController { constructor(private readonly usersService: UsersService) {} + @ApiCreatedResponse({ + type: User, + }) @SerializeOptions({ groups: ['admin'], }) @@ -47,6 +59,9 @@ export class UsersController { return this.usersService.create(createProfileDto); } + @ApiOkResponse({ + type: InfinityPaginationResponse(User), + }) @SerializeOptions({ groups: ['admin'], }) @@ -54,7 +69,7 @@ export class UsersController { @HttpCode(HttpStatus.OK) async findAll( @Query() query: QueryUserDto, - ): Promise> { + ): Promise> { const page = query?.page ?? 1; let limit = query?.limit ?? 10; if (limit > 50) { @@ -74,6 +89,9 @@ export class UsersController { ); } + @ApiOkResponse({ + type: User, + }) @SerializeOptions({ groups: ['admin'], }) @@ -88,6 +106,9 @@ export class UsersController { return this.usersService.findOne({ id }); } + @ApiOkResponse({ + type: User, + }) @SerializeOptions({ groups: ['admin'], }) diff --git a/src/utils/document-entity-helper.ts b/src/utils/document-entity-helper.ts index e40e015a4..54a8c32ed 100644 --- a/src/utils/document-entity-helper.ts +++ b/src/utils/document-entity-helper.ts @@ -1,6 +1,10 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; export class EntityDocumentHelper { + @ApiResponseProperty({ + type: String, + }) @Transform( (value) => { if ('value' in value) { diff --git a/src/utils/dto/infinity-pagination-response.dto.ts b/src/utils/dto/infinity-pagination-response.dto.ts new file mode 100644 index 000000000..ada3f771a --- /dev/null +++ b/src/utils/dto/infinity-pagination-response.dto.ts @@ -0,0 +1,27 @@ +import { Type } from '@nestjs/common'; +import { ApiResponseProperty } from '@nestjs/swagger'; + +export class InfinityPaginationResponseDto { + data: T[]; + hasNextPage: boolean; +} + +export function InfinityPaginationResponse(classReference: Type) { + abstract class Pagination { + @ApiResponseProperty({ type: [classReference] }) + data!: T[]; + + @ApiResponseProperty({ + type: Boolean, + example: true, + }) + hasNextPage: boolean; + } + + Object.defineProperty(Pagination, 'name', { + writable: false, + value: `InfinityPagination${classReference.name}ResponseDto`, + }); + + return Pagination; +} diff --git a/src/utils/infinity-pagination.ts b/src/utils/infinity-pagination.ts index 1b40cce29..f5d713c84 100644 --- a/src/utils/infinity-pagination.ts +++ b/src/utils/infinity-pagination.ts @@ -1,10 +1,10 @@ import { IPaginationOptions } from './types/pagination-options'; -import { InfinityPaginationResultType } from './types/infinity-pagination-result.type'; +import { InfinityPaginationResponseDto } from './dto/infinity-pagination-response.dto'; export const infinityPagination = ( data: T[], options: IPaginationOptions, -): InfinityPaginationResultType => { +): InfinityPaginationResponseDto => { return { data, hasNextPage: data.length === options.limit, diff --git a/src/utils/types/infinity-pagination-result.type.ts b/src/utils/types/infinity-pagination-result.type.ts deleted file mode 100644 index 273fd69bb..000000000 --- a/src/utils/types/infinity-pagination-result.type.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type InfinityPaginationResultType = Readonly<{ - data: T[]; - hasNextPage: boolean; -}>;