Updating controllers to use separate req class for transformation and validation

This commit is contained in:
Collin Duncan 2023-10-10 11:51:03 +02:00
parent 39bed45814
commit d8370ee4b8
No known key found for this signature in database
5 changed files with 121 additions and 31 deletions

View file

@ -10,7 +10,7 @@ async function bootstrap() {
const config = app.get(ConfigService)
const port = config.get('PORT', 3000)
app.enableShutdownHooks()
app.useGlobalPipes(new ValidationPipe())
app.useGlobalPipes(new ValidationPipe({ transform: true }))
app.useGlobalInterceptors(new CustomResponseTransformInterceptor())
await app.listen(port, () => console.log(`Listening on port ${port}`))
}

View file

@ -9,13 +9,37 @@ import {
Post,
Query,
UseInterceptors,
UsePipes,
ValidationPipe,
} from '@nestjs/common'
import { IsEnum, IsOptional, IsString, Matches } from 'class-validator'
import { DayOfWeek, RecurringReservation } from './entity'
import { DayOfWeek } from './entity'
import { RecurringReservationsService } from './service'
export class CreateRecurringReservationRequest {
@IsString()
ownerId: string
@IsEnum(DayOfWeek)
dayOfWeek: number
@IsString()
@Matches(/[012][0-9]:[0-5][0-9]/)
timeStart: string
@IsOptional()
@IsString()
@Matches(/[012][0-9]:[0-5][0-9]/)
timeEnd?: string
@IsOptional()
@IsString()
opponentId?: string
@IsOptional()
@IsString()
opponentName?: string
}
@Controller('recurring-reservations')
@UseInterceptors(ClassSerializerInterceptor)
export class RecurringReservationsController {
@ -38,15 +62,8 @@ export class RecurringReservationsController {
}
@Post()
@UsePipes(
new ValidationPipe({
transform: true,
transformOptions: { groups: ['password'] },
groups: ['password'],
}),
)
async createReservation(@Body() recurringReservation: RecurringReservation) {
await this.recurringReservationsService.create(recurringReservation)
async createReservation(@Body() req: CreateRecurringReservationRequest) {
await this.recurringReservationsService.create(req)
return 'Recurring reservation created'
}

View file

@ -30,8 +30,30 @@ export class RecurringReservationsService {
.getMany()
}
create(recurringReservation: RecurringReservation) {
return this.recurringReservationsRepository.save(recurringReservation)
async create({
ownerId,
dayOfWeek,
timeStart,
timeEnd,
opponentId = '-1',
opponentName = 'Gast',
}: {
ownerId: string
dayOfWeek: DayOfWeek
timeStart: string
timeEnd?: string
opponentId?: string
opponentName?: string
}) {
const recRes = this.recurringReservationsRepository.create({
ownerId,
dayOfWeek,
timeStart,
timeEnd: timeEnd ?? timeStart,
opponentId,
opponentName,
})
return await this.recurringReservationsRepository.save(recRes)
}
scheduleReservation(recurringReservation: RecurringReservation) {

View file

@ -10,14 +10,13 @@ import {
Post,
Query,
UseInterceptors,
UsePipes,
ValidationPipe,
} from '@nestjs/common'
import { Queue } from 'bull'
import { Transform } from 'class-transformer'
import { IsBoolean, IsOptional } from 'class-validator'
import { Transform, TransformationType } from 'class-transformer'
import { IsBoolean, IsOptional, IsString } from 'class-validator'
import { Dayjs } from 'dayjs'
import dayjs from '../common/dayjs'
import { LoggerService } from '../logger/service.logger'
import { RESERVATIONS_QUEUE_NAME } from './config'
import { Reservation } from './entity'
@ -34,6 +33,44 @@ export class GetReservationsQueryParams {
readonly schedulable?: boolean
}
export class CreateReservationRequest {
@IsString()
ownerId: string
@Transform(({ value, type }) => {
switch (type) {
case TransformationType.PLAIN_TO_CLASS:
return dayjs(value)
case TransformationType.CLASS_TO_PLAIN:
return value.format()
default:
return value
}
})
dateRangeStart: Dayjs
@IsOptional()
@Transform(({ value, type }) => {
switch (type) {
case TransformationType.PLAIN_TO_CLASS:
return dayjs(value)
case TransformationType.CLASS_TO_PLAIN:
return value.format()
default:
return value
}
})
dateRangeEnd?: Dayjs
@IsOptional()
@IsString()
opponentId?: string
@IsOptional()
@IsString()
opponentName?: string
}
@Controller('reservations')
@UseInterceptors(ClassSerializerInterceptor)
export class ReservationsController {
@ -66,21 +103,15 @@ export class ReservationsController {
}
@Post()
@UsePipes(
new ValidationPipe({
transform: true,
transformOptions: { groups: ['password'] },
groups: ['password'],
}),
)
async createReservation(@Body() reservation: Reservation) {
await this.reservationsService.create(reservation)
async createReservation(@Body() req: CreateReservationRequest) {
console.log(req)
const reservation = await this.reservationsService.create(req)
if (!reservation.isAvailableForReservation()) {
this.loggerService.debug('Reservation not available for reservation')
return 'Reservation saved'
}
this.loggerService.debug('Reservation is available for reservation')
await this.reservationsQueue.add(reservation)
// await this.reservationsQueue.add(reservation)
return 'Reservation queued'
}

View file

@ -1,5 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Dayjs } from 'dayjs'
import { Repository } from 'typeorm'
import dayjs from '../common/dayjs'
@ -68,8 +69,27 @@ export class ReservationsService {
.getMany()
}
async create(reservation: Reservation) {
return await this.reservationsRepository.save(reservation)
async create({
ownerId,
dateRangeStart,
dateRangeEnd,
opponentId = '-1',
opponentName = 'Gast',
}: {
ownerId: string
dateRangeStart: Dayjs
dateRangeEnd?: Dayjs
opponentId?: string
opponentName?: string
}) {
const res = this.reservationsRepository.create({
ownerId,
dateRangeStart,
dateRangeEnd: dateRangeEnd ?? dateRangeStart,
opponentId,
opponentName,
})
return await this.reservationsRepository.save(res)
}
async update(reservationId: string, update: Partial<Reservation>) {