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 config = app.get(ConfigService)
const port = config.get('PORT', 3000) const port = config.get('PORT', 3000)
app.enableShutdownHooks() app.enableShutdownHooks()
app.useGlobalPipes(new ValidationPipe()) app.useGlobalPipes(new ValidationPipe({ transform: true }))
app.useGlobalInterceptors(new CustomResponseTransformInterceptor()) app.useGlobalInterceptors(new CustomResponseTransformInterceptor())
await app.listen(port, () => console.log(`Listening on port ${port}`)) await app.listen(port, () => console.log(`Listening on port ${port}`))
} }

View file

@ -9,13 +9,37 @@ import {
Post, Post,
Query, Query,
UseInterceptors, UseInterceptors,
UsePipes,
ValidationPipe,
} from '@nestjs/common' } from '@nestjs/common'
import { IsEnum, IsOptional, IsString, Matches } from 'class-validator'
import { DayOfWeek, RecurringReservation } from './entity' import { DayOfWeek } from './entity'
import { RecurringReservationsService } from './service' 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') @Controller('recurring-reservations')
@UseInterceptors(ClassSerializerInterceptor) @UseInterceptors(ClassSerializerInterceptor)
export class RecurringReservationsController { export class RecurringReservationsController {
@ -38,15 +62,8 @@ export class RecurringReservationsController {
} }
@Post() @Post()
@UsePipes( async createReservation(@Body() req: CreateRecurringReservationRequest) {
new ValidationPipe({ await this.recurringReservationsService.create(req)
transform: true,
transformOptions: { groups: ['password'] },
groups: ['password'],
}),
)
async createReservation(@Body() recurringReservation: RecurringReservation) {
await this.recurringReservationsService.create(recurringReservation)
return 'Recurring reservation created' return 'Recurring reservation created'
} }

View file

@ -30,8 +30,30 @@ export class RecurringReservationsService {
.getMany() .getMany()
} }
create(recurringReservation: RecurringReservation) { async create({
return this.recurringReservationsRepository.save(recurringReservation) 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) { scheduleReservation(recurringReservation: RecurringReservation) {

View file

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

View file

@ -1,5 +1,6 @@
import { Inject, Injectable } from '@nestjs/common' import { Inject, Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm' import { InjectRepository } from '@nestjs/typeorm'
import { Dayjs } from 'dayjs'
import { Repository } from 'typeorm' import { Repository } from 'typeorm'
import dayjs from '../common/dayjs' import dayjs from '../common/dayjs'
@ -68,8 +69,27 @@ export class ReservationsService {
.getMany() .getMany()
} }
async create(reservation: Reservation) { async create({
return await this.reservationsRepository.save(reservation) 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>) { async update(reservationId: string, update: Partial<Reservation>) {