update swagger

This commit is contained in:
2026-07-02 20:21:12 +03:30
parent 8e2e43e12b
commit 1f06b378e6
18 changed files with 346 additions and 34 deletions
+14
View File
@@ -5,21 +5,32 @@ import {
ApiProtectedEndpoint, ApiProtectedEndpoint,
ApiPublicEndpoint, ApiPublicEndpoint,
} from '../swagger/decorators/swagger-auth.decorator'; } from '../swagger/decorators/swagger-auth.decorator';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardMessageResponse,
ApiStandardOkResponse,
ApiStandardTooManyRequestsResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { CurrentUser } from './decorators/current-user.decorator'; import { CurrentUser } from './decorators/current-user.decorator';
import { Public } from './decorators/public.decorator'; import { Public } from './decorators/public.decorator';
import { AuthTokensResponseDto } from './dto/auth-tokens-response.dto';
import { RefreshTokenDto } from './dto/refresh-token.dto'; import { RefreshTokenDto } from './dto/refresh-token.dto';
import { RequestOtpDto } from './dto/request-otp.dto'; import { RequestOtpDto } from './dto/request-otp.dto';
import { VerifyOtpDto } from './dto/verify-otp.dto'; import { VerifyOtpDto } from './dto/verify-otp.dto';
import { AuthUser } from './interfaces/auth-user.interface'; import { AuthUser } from './interfaces/auth-user.interface';
@ApiTags('Auth') @ApiTags('Auth')
@ApiStandardController()
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private readonly authService: AuthService) {} constructor(private readonly authService: AuthService) {}
@Public() @Public()
@ApiPublicEndpoint('Request OTP code via SMS') @ApiPublicEndpoint('Request OTP code via SMS')
@ApiStandardMessageResponse('OTP sent')
@ApiStandardTooManyRequestsResponse()
@Post('otp/request') @Post('otp/request')
requestOtp(@Body() dto: RequestOtpDto) { requestOtp(@Body() dto: RequestOtpDto) {
return this.authService.requestOtp(dto.mobile); return this.authService.requestOtp(dto.mobile);
@@ -27,6 +38,7 @@ export class AuthController {
@Public() @Public()
@ApiPublicEndpoint('Verify OTP and receive access/refresh tokens') @ApiPublicEndpoint('Verify OTP and receive access/refresh tokens')
@ApiStandardOkResponse(AuthTokensResponseDto)
@Post('otp/verify') @Post('otp/verify')
verifyOtp(@Body() dto: VerifyOtpDto) { verifyOtp(@Body() dto: VerifyOtpDto) {
return this.authService.verifyOtp(dto); return this.authService.verifyOtp(dto);
@@ -34,6 +46,7 @@ export class AuthController {
@Public() @Public()
@ApiPublicEndpoint('Refresh access token') @ApiPublicEndpoint('Refresh access token')
@ApiStandardOkResponse(AuthTokensResponseDto)
@Post('refresh') @Post('refresh')
refresh(@Body() dto: RefreshTokenDto) { refresh(@Body() dto: RefreshTokenDto) {
return this.authService.refresh(dto.refreshToken); return this.authService.refresh(dto.refreshToken);
@@ -41,6 +54,7 @@ export class AuthController {
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiProtectedEndpoint('Logout and invalidate refresh token') @ApiProtectedEndpoint('Logout and invalidate refresh token')
@ApiStandardEmptyResponse()
@Post('logout') @Post('logout')
logout(@CurrentUser() user: AuthUser, @Body() dto: RefreshTokenDto) { logout(@CurrentUser() user: AuthUser, @Body() dto: RefreshTokenDto) {
return this.authService.logout(user.id, dto.refreshToken); return this.authService.logout(user.id, dto.refreshToken);
+30
View File
@@ -0,0 +1,30 @@
import { ApiProperty } from '@nestjs/swagger';
import { UserRole } from '../../users/enums/user-role.enum';
class AuthUserResponseDto {
@ApiProperty({ format: 'uuid' })
id: string;
@ApiProperty()
firstName: string;
@ApiProperty()
lastName: string;
@ApiProperty()
mobile: string;
@ApiProperty({ enum: UserRole })
role: UserRole;
}
export class AuthTokensResponseDto {
@ApiProperty()
accessToken: string;
@ApiProperty()
refreshToken: string;
@ApiProperty({ type: AuthUserResponseDto })
user: AuthUserResponseDto;
}
+1 -32
View File
@@ -1,10 +1,4 @@
import { applyDecorators, Type } from '@nestjs/common'; import { ApiProperty } from '@nestjs/swagger';
import {
ApiExtraModels,
ApiOkResponse,
ApiProperty,
getSchemaPath,
} from '@nestjs/swagger';
export class ApiSuccessResponseDto<T = unknown> { export class ApiSuccessResponseDto<T = unknown> {
@ApiProperty({ example: true }) @ApiProperty({ example: true })
@@ -43,28 +37,3 @@ export class ApiErrorResponseDto {
@ApiProperty({ example: '/api/users' }) @ApiProperty({ example: '/api/users' })
path: string; path: string;
} }
export const ApiStandardOkResponse = <TModel extends Type<unknown>>(
model: TModel,
options?: { isArray?: boolean },
) =>
applyDecorators(
ApiExtraModels(ApiSuccessResponseDto, model),
ApiOkResponse({
schema: {
allOf: [
{ $ref: getSchemaPath(ApiSuccessResponseDto) },
{
properties: {
data: options?.isArray
? {
type: 'array',
items: { $ref: getSchemaPath(model) },
}
: { $ref: getSchemaPath(model) },
},
},
],
},
}),
);
+11
View File
@@ -20,9 +20,16 @@ import { UserRole } from '../users/enums/user-role.enum';
import { CustomersService } from './customers.service'; import { CustomersService } from './customers.service';
import { UpdateCustomerDto } from './dto/update-customer.dto'; import { UpdateCustomerDto } from './dto/update-customer.dto';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { Customer } from './entities/customer.entity';
@ApiTags('Customers') @ApiTags('Customers')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('customers') @Controller('customers')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class CustomersController { export class CustomersController {
@@ -30,11 +37,13 @@ export class CustomersController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.CUSTOMERS_READ) @Permissions(PermissionCode.CUSTOMERS_READ)
@ApiStandardOkResponse(Customer, { isArray: true })
@Get() @Get()
findAll() { findAll() {
return this.customersService.findAll(); return this.customersService.findAll();
} }
@ApiStandardOkResponse(Customer)
@Get(':id') @Get(':id')
findOne( findOne(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -43,6 +52,7 @@ export class CustomersController {
return this.customersService.findOne(id, user); return this.customersService.findOne(id, user);
} }
@ApiStandardOkResponse(Customer)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -54,6 +64,7 @@ export class CustomersController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.CUSTOMERS_DELETE) @Permissions(PermissionCode.CUSTOMERS_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.customersService.remove(id); return this.customersService.remove(id);
+12
View File
@@ -23,9 +23,16 @@ import { FindReservesQueryDto } from './dto/find-reserves-query.dto';
import { UpdateReserveDto } from './dto/update-reserve.dto'; import { UpdateReserveDto } from './dto/update-reserve.dto';
import { ReservesService } from './reserves.service'; import { ReservesService } from './reserves.service';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { ReserveStatusHistory } from './entities/reserve-status-history.entity';
import { Reserve } from './entities/reserve.entity';
@ApiTags('Reserves') @ApiTags('Reserves')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('reserves') @Controller('reserves')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class ReservesController { export class ReservesController {
@@ -33,6 +40,7 @@ export class ReservesController {
@Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER) @Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER)
@Permissions(PermissionCode.RESERVES_WRITE) @Permissions(PermissionCode.RESERVES_WRITE)
@ApiStandardOkResponse(Reserve)
@Post() @Post()
create( create(
@Body() createReserveDto: CreateReserveDto, @Body() createReserveDto: CreateReserveDto,
@@ -43,6 +51,7 @@ export class ReservesController {
@Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER) @Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER)
@Permissions(PermissionCode.RESERVES_READ) @Permissions(PermissionCode.RESERVES_READ)
@ApiStandardOkResponse(Reserve, { isArray: true })
@Get() @Get()
findAll( findAll(
@Query() query: FindReservesQueryDto, @Query() query: FindReservesQueryDto,
@@ -53,6 +62,7 @@ export class ReservesController {
@Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER) @Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER)
@Permissions(PermissionCode.RESERVES_READ) @Permissions(PermissionCode.RESERVES_READ)
@ApiStandardOkResponse(ReserveStatusHistory, { isArray: true })
@Get(':id/status-history') @Get(':id/status-history')
findStatusHistory( findStatusHistory(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -63,6 +73,7 @@ export class ReservesController {
@Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER) @Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER)
@Permissions(PermissionCode.RESERVES_READ) @Permissions(PermissionCode.RESERVES_READ)
@ApiStandardOkResponse(Reserve)
@Get(':id') @Get(':id')
findOne( findOne(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -73,6 +84,7 @@ export class ReservesController {
@Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER) @Roles(UserRole.ADMIN, UserRole.SALON, UserRole.CUSTOMER)
@Permissions(PermissionCode.RESERVES_WRITE) @Permissions(PermissionCode.RESERVES_WRITE)
@ApiStandardOkResponse(Reserve)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
+12
View File
@@ -26,9 +26,16 @@ import { UpdateSalonDto } from './dto/update-salon.dto';
import { SalonsService } from './salons.service'; import { SalonsService } from './salons.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { Salon } from './entities/salon.entity';
@ApiTags('Salons') @ApiTags('Salons')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('salons') @Controller('salons')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SalonsController { export class SalonsController {
@@ -37,6 +44,7 @@ export class SalonsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SALONS_WRITE) @Permissions(PermissionCode.SALONS_WRITE)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(Salon)
@Post() @Post()
create( create(
@Body() createSalonDto: CreateSalonDto, @Body() createSalonDto: CreateSalonDto,
@@ -47,6 +55,7 @@ export class SalonsController {
@Public() @Public()
@ApiPublicEndpoint('List all salons') @ApiPublicEndpoint('List all salons')
@ApiStandardOkResponse(Salon, { isArray: true })
@Get() @Get()
findAll(@OptionalCurrentUser() user?: AuthUser) { findAll(@OptionalCurrentUser() user?: AuthUser) {
return this.salonsService.findAll(user); return this.salonsService.findAll(user);
@@ -54,6 +63,7 @@ export class SalonsController {
@Public() @Public()
@ApiPublicEndpoint('Get salon by ID') @ApiPublicEndpoint('Get salon by ID')
@ApiStandardOkResponse(Salon)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.salonsService.findOne(id); return this.salonsService.findOne(id);
@@ -61,6 +71,7 @@ export class SalonsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SALONS_WRITE) @Permissions(PermissionCode.SALONS_WRITE)
@ApiStandardOkResponse(Salon)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -72,6 +83,7 @@ export class SalonsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SALONS_DELETE) @Permissions(PermissionCode.SALONS_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove( remove(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -20,15 +20,22 @@ import { FindSentMessagesQueryDto } from './dto/find-sent-messages-query.dto';
import { UpdateSentMessageDto } from './dto/update-sent-message.dto'; import { UpdateSentMessageDto } from './dto/update-sent-message.dto';
import { SentMessagesService } from './sent-messages.service'; import { SentMessagesService } from './sent-messages.service';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { SentMessage } from './entities/sent-message.entity';
@ApiTags('Sent Messages') @ApiTags('Sent Messages')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('sent-messages') @Controller('sent-messages')
@UseGuards(RolesGuard) @UseGuards(RolesGuard)
export class SentMessagesController { export class SentMessagesController {
constructor(private readonly sentMessagesService: SentMessagesService) {} constructor(private readonly sentMessagesService: SentMessagesService) {}
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@ApiStandardOkResponse(SentMessage)
@Post() @Post()
create( create(
@Body() createDto: CreateSentMessageDto, @Body() createDto: CreateSentMessageDto,
@@ -38,6 +45,7 @@ export class SentMessagesController {
} }
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@ApiStandardOkResponse(SentMessage, { isArray: true })
@Get() @Get()
findAll( findAll(
@Query() query: FindSentMessagesQueryDto, @Query() query: FindSentMessagesQueryDto,
@@ -47,6 +55,7 @@ export class SentMessagesController {
} }
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@ApiStandardOkResponse(SentMessage)
@Get(':id') @Get(':id')
findOne( findOne(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -56,6 +65,7 @@ export class SentMessagesController {
} }
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@ApiStandardOkResponse(SentMessage)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
+18
View File
@@ -26,9 +26,17 @@ import { UpdateServiceDto } from './dto/update-service.dto';
import { ServicesService } from './services.service'; import { ServicesService } from './services.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { ServiceSkill } from './entities/service-skill.entity';
import { Service } from './entities/service.entity';
@ApiTags('Services') @ApiTags('Services')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('services') @Controller('services')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class ServicesController { export class ServicesController {
@@ -36,6 +44,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(Service)
@Post() @Post()
create( create(
@Body() createServiceDto: CreateServiceDto, @Body() createServiceDto: CreateServiceDto,
@@ -46,6 +55,7 @@ export class ServicesController {
@Public() @Public()
@ApiPublicEndpoint('List all services') @ApiPublicEndpoint('List all services')
@ApiStandardOkResponse(Service, { isArray: true })
@Get() @Get()
findAll() { findAll() {
return this.servicesService.findAll(); return this.servicesService.findAll();
@@ -53,6 +63,7 @@ export class ServicesController {
@Public() @Public()
@ApiPublicEndpoint('Get service by ID') @ApiPublicEndpoint('Get service by ID')
@ApiStandardOkResponse(Service)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.servicesService.findOne(id); return this.servicesService.findOne(id);
@@ -60,6 +71,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(Service)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -71,6 +83,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_DELETE) @Permissions(PermissionCode.SERVICES_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove( remove(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -81,6 +94,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(ServiceSkill)
@Post(':serviceId/skills') @Post(':serviceId/skills')
createSkill( createSkill(
@Param('serviceId', ParseUUIDPipe) serviceId: string, @Param('serviceId', ParseUUIDPipe) serviceId: string,
@@ -96,6 +110,7 @@ export class ServicesController {
@Public() @Public()
@ApiPublicEndpoint('List skills for a service') @ApiPublicEndpoint('List skills for a service')
@ApiStandardOkResponse(ServiceSkill, { isArray: true })
@Get(':serviceId/skills') @Get(':serviceId/skills')
findSkills(@Param('serviceId', ParseUUIDPipe) serviceId: string) { findSkills(@Param('serviceId', ParseUUIDPipe) serviceId: string) {
return this.servicesService.findSkills(serviceId); return this.servicesService.findSkills(serviceId);
@@ -103,6 +118,7 @@ export class ServicesController {
@Public() @Public()
@ApiPublicEndpoint('Get a service skill by ID') @ApiPublicEndpoint('Get a service skill by ID')
@ApiStandardOkResponse(ServiceSkill)
@Get(':serviceId/skills/:skillId') @Get(':serviceId/skills/:skillId')
findSkill( findSkill(
@Param('serviceId', ParseUUIDPipe) serviceId: string, @Param('serviceId', ParseUUIDPipe) serviceId: string,
@@ -113,6 +129,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(ServiceSkill)
@Patch(':serviceId/skills/:skillId') @Patch(':serviceId/skills/:skillId')
updateSkill( updateSkill(
@Param('serviceId', ParseUUIDPipe) serviceId: string, @Param('serviceId', ParseUUIDPipe) serviceId: string,
@@ -130,6 +147,7 @@ export class ServicesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_DELETE) @Permissions(PermissionCode.SERVICES_DELETE)
@ApiStandardEmptyResponse()
@Delete(':serviceId/skills/:skillId') @Delete(':serviceId/skills/:skillId')
removeSkill( removeSkill(
@Param('serviceId', ParseUUIDPipe) serviceId: string, @Param('serviceId', ParseUUIDPipe) serviceId: string,
@@ -24,9 +24,16 @@ import { FindSmsTemplatesQueryDto } from './dto/find-sms-templates-query.dto';
import { UpdateSmsTemplateDto } from './dto/update-sms-template.dto'; import { UpdateSmsTemplateDto } from './dto/update-sms-template.dto';
import { SmsTemplatesService } from './sms-templates.service'; import { SmsTemplatesService } from './sms-templates.service';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { SmsTemplate } from './entities/sms-template.entity';
@ApiTags('SMS Templates') @ApiTags('SMS Templates')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('sms-templates') @Controller('sms-templates')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SmsTemplatesController { export class SmsTemplatesController {
@@ -34,6 +41,7 @@ export class SmsTemplatesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SMS_TEMPLATES_WRITE) @Permissions(PermissionCode.SMS_TEMPLATES_WRITE)
@ApiStandardOkResponse(SmsTemplate)
@Post() @Post()
create( create(
@Body() createDto: CreateSmsTemplateDto, @Body() createDto: CreateSmsTemplateDto,
@@ -44,6 +52,7 @@ export class SmsTemplatesController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SMS_TEMPLATES_READ) @Permissions(PermissionCode.SMS_TEMPLATES_READ)
@ApiStandardOkResponse(SmsTemplate, { isArray: true })
@Get() @Get()
findAll(@Query() query: FindSmsTemplatesQueryDto) { findAll(@Query() query: FindSmsTemplatesQueryDto) {
return this.smsTemplatesService.findAll(query); return this.smsTemplatesService.findAll(query);
@@ -51,6 +60,7 @@ export class SmsTemplatesController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SMS_TEMPLATES_READ) @Permissions(PermissionCode.SMS_TEMPLATES_READ)
@ApiStandardOkResponse(SmsTemplate)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.smsTemplatesService.findOne(id); return this.smsTemplatesService.findOne(id);
@@ -58,6 +68,7 @@ export class SmsTemplatesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SMS_TEMPLATES_WRITE) @Permissions(PermissionCode.SMS_TEMPLATES_WRITE)
@ApiStandardOkResponse(SmsTemplate)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -69,6 +80,7 @@ export class SmsTemplatesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SMS_TEMPLATES_WRITE) @Permissions(PermissionCode.SMS_TEMPLATES_WRITE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove( remove(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
+12
View File
@@ -25,9 +25,16 @@ import { UpdateStylistDto } from './dto/update-stylist.dto';
import { StylistsService } from './stylists.service'; import { StylistsService } from './stylists.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { Stylist } from './entities/stylist.entity';
@ApiTags('Stylists') @ApiTags('Stylists')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('stylists') @Controller('stylists')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class StylistsController { export class StylistsController {
@@ -35,6 +42,7 @@ export class StylistsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.STYLISTS_WRITE) @Permissions(PermissionCode.STYLISTS_WRITE)
@ApiStandardOkResponse(Stylist)
@Post() @Post()
create( create(
@Body() createStylistDto: CreateStylistDto, @Body() createStylistDto: CreateStylistDto,
@@ -46,6 +54,7 @@ export class StylistsController {
@Public() @Public()
@ApiPublicEndpoint('List stylists, optionally filtered by salon') @ApiPublicEndpoint('List stylists, optionally filtered by salon')
@ApiQuery({ name: 'salonId', required: false, type: String, format: 'uuid' }) @ApiQuery({ name: 'salonId', required: false, type: String, format: 'uuid' })
@ApiStandardOkResponse(Stylist, { isArray: true })
@Get() @Get()
findAll(@Query('salonId', new ParseUUIDPipe({ optional: true })) salonId?: string) { findAll(@Query('salonId', new ParseUUIDPipe({ optional: true })) salonId?: string) {
return this.stylistsService.findAll(salonId); return this.stylistsService.findAll(salonId);
@@ -53,6 +62,7 @@ export class StylistsController {
@Public() @Public()
@ApiPublicEndpoint('Get stylist by ID') @ApiPublicEndpoint('Get stylist by ID')
@ApiStandardOkResponse(Stylist)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.stylistsService.findOne(id); return this.stylistsService.findOne(id);
@@ -60,6 +70,7 @@ export class StylistsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.STYLISTS_WRITE) @Permissions(PermissionCode.STYLISTS_WRITE)
@ApiStandardOkResponse(Stylist)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -71,6 +82,7 @@ export class StylistsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.STYLISTS_DELETE) @Permissions(PermissionCode.STYLISTS_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove( remove(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
export class SalonSmsBalanceDto {
@ApiProperty({ example: 100 })
freeSmsRemaining: number;
@ApiProperty({ example: 250 })
purchasedSmsRemaining: number;
@ApiProperty({ example: 350 })
totalRemaining: number;
}
@@ -21,9 +21,17 @@ import { PurchaseSmsPackageDto } from './dto/purchase-sms-package.dto';
import { PurchaseSubscriptionDto } from './dto/purchase-subscription.dto'; import { PurchaseSubscriptionDto } from './dto/purchase-subscription.dto';
import { SalonSubscriptionsService } from './salon-subscriptions.service'; import { SalonSubscriptionsService } from './salon-subscriptions.service';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { SalonSmsBalanceDto } from './dto/salon-sms-balance.dto';
import { SalonSmsPurchase } from './entities/salon-sms-purchase.entity';
import { SalonSubscription } from './entities/salon-subscription.entity';
@ApiTags('Salon Subscriptions') @ApiTags('Salon Subscriptions')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('salon-subscriptions') @Controller('salon-subscriptions')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SalonSubscriptionsController { export class SalonSubscriptionsController {
@@ -34,6 +42,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(SalonSubscription)
@Post('purchase') @Post('purchase')
purchaseSubscription( purchaseSubscription(
@Body() dto: PurchaseSubscriptionDto, @Body() dto: PurchaseSubscriptionDto,
@@ -44,6 +53,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardOkResponse(SalonSmsPurchase)
@Post('sms/purchase') @Post('sms/purchase')
purchaseSmsPackage( purchaseSmsPackage(
@Body() dto: PurchaseSmsPackageDto, @Body() dto: PurchaseSmsPackageDto,
@@ -55,6 +65,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_READ) @Permissions(PermissionCode.SUBSCRIPTIONS_READ)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(SalonSubscription, { isArray: true })
@Get('salon/:salonId') @Get('salon/:salonId')
findAllForSalon( findAllForSalon(
@Param('salonId', ParseUUIDPipe) salonId: string, @Param('salonId', ParseUUIDPipe) salonId: string,
@@ -66,6 +77,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_READ) @Permissions(PermissionCode.SUBSCRIPTIONS_READ)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(SalonSubscription, { nullable: true })
@Get('salon/:salonId/active') @Get('salon/:salonId/active')
findActiveForSalon( findActiveForSalon(
@Param('salonId', ParseUUIDPipe) salonId: string, @Param('salonId', ParseUUIDPipe) salonId: string,
@@ -77,6 +89,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_READ) @Permissions(PermissionCode.SUBSCRIPTIONS_READ)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(SalonSmsBalanceDto)
@Get('salon/:salonId/sms-balance') @Get('salon/:salonId/sms-balance')
getSmsBalance( getSmsBalance(
@Param('salonId', ParseUUIDPipe) salonId: string, @Param('salonId', ParseUUIDPipe) salonId: string,
@@ -87,6 +100,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_READ) @Permissions(PermissionCode.SUBSCRIPTIONS_READ)
@ApiStandardOkResponse(SalonSmsPurchase, { isArray: true })
@Get('salon/:salonId/sms-purchases') @Get('salon/:salonId/sms-purchases')
findSmsPurchasesForSalon( findSmsPurchasesForSalon(
@Param('salonId', ParseUUIDPipe) salonId: string, @Param('salonId', ParseUUIDPipe) salonId: string,
@@ -101,6 +115,7 @@ export class SalonSubscriptionsController {
@Roles(UserRole.ADMIN, UserRole.SALON) @Roles(UserRole.ADMIN, UserRole.SALON)
@Permissions(PermissionCode.SUBSCRIPTIONS_READ) @Permissions(PermissionCode.SUBSCRIPTIONS_READ)
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiStandardOkResponse(SalonSubscription)
@Get(':id') @Get(':id')
findOne( findOne(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -23,9 +23,16 @@ import { UpdateSmsPackageDto } from './dto/update-sms-package.dto';
import { SmsPackagesService } from './sms-packages.service'; import { SmsPackagesService } from './sms-packages.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { SmsPackage } from './entities/sms-package.entity';
@ApiTags('SMS Packages') @ApiTags('SMS Packages')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('sms-packages') @Controller('sms-packages')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SmsPackagesController { export class SmsPackagesController {
@@ -33,6 +40,7 @@ export class SmsPackagesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardOkResponse(SmsPackage)
@Post() @Post()
create(@Body() dto: CreateSmsPackageDto) { create(@Body() dto: CreateSmsPackageDto) {
return this.smsPackagesService.create(dto); return this.smsPackagesService.create(dto);
@@ -41,6 +49,7 @@ export class SmsPackagesController {
@Public() @Public()
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiPublicEndpoint('List active SMS packages') @ApiPublicEndpoint('List active SMS packages')
@ApiStandardOkResponse(SmsPackage, { isArray: true })
@Get() @Get()
findAll() { findAll() {
return this.smsPackagesService.findAll(true); return this.smsPackagesService.findAll(true);
@@ -49,6 +58,7 @@ export class SmsPackagesController {
@Public() @Public()
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiPublicEndpoint('Get SMS package by ID') @ApiPublicEndpoint('Get SMS package by ID')
@ApiStandardOkResponse(SmsPackage)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.smsPackagesService.findOne(id); return this.smsPackagesService.findOne(id);
@@ -56,6 +66,7 @@ export class SmsPackagesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardOkResponse(SmsPackage)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -66,6 +77,7 @@ export class SmsPackagesController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.smsPackagesService.remove(id); return this.smsPackagesService.remove(id);
@@ -25,9 +25,16 @@ import { UpdateSubscriptionPlanDto } from './dto/update-subscription-plan.dto';
import { SubscriptionPlansService } from './subscription-plans.service'; import { SubscriptionPlansService } from './subscription-plans.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { SubscriptionPlan } from './entities/subscription-plan.entity';
@ApiTags('Subscription Plans') @ApiTags('Subscription Plans')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('subscription-plans') @Controller('subscription-plans')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SubscriptionPlansController { export class SubscriptionPlansController {
@@ -37,6 +44,7 @@ export class SubscriptionPlansController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardOkResponse(SubscriptionPlan)
@Post() @Post()
create(@Body() dto: CreateSubscriptionPlanDto) { create(@Body() dto: CreateSubscriptionPlanDto) {
return this.subscriptionPlansService.create(dto); return this.subscriptionPlansService.create(dto);
@@ -45,6 +53,7 @@ export class SubscriptionPlansController {
@Public() @Public()
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiPublicEndpoint('List active subscription plans') @ApiPublicEndpoint('List active subscription plans')
@ApiStandardOkResponse(SubscriptionPlan, { isArray: true })
@Get() @Get()
findAll() { findAll() {
return this.subscriptionPlansService.findAll(true); return this.subscriptionPlansService.findAll(true);
@@ -53,6 +62,7 @@ export class SubscriptionPlansController {
@Public() @Public()
@AllowWithoutSubscription() @AllowWithoutSubscription()
@ApiPublicEndpoint('Get subscription plan by ID') @ApiPublicEndpoint('Get subscription plan by ID')
@ApiStandardOkResponse(SubscriptionPlan)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.subscriptionPlansService.findOne(id); return this.subscriptionPlansService.findOne(id);
@@ -60,6 +70,7 @@ export class SubscriptionPlansController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardOkResponse(SubscriptionPlan)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -70,6 +81,7 @@ export class SubscriptionPlansController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SUBSCRIPTIONS_WRITE) @Permissions(PermissionCode.SUBSCRIPTIONS_WRITE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.subscriptionPlansService.remove(id); return this.subscriptionPlansService.remove(id);
+13
View File
@@ -26,9 +26,16 @@ import { UpdateServiceSuggestionDto } from './dto/update-service-suggestion.dto'
import { SuggestionsService } from './suggestions.service'; import { SuggestionsService } from './suggestions.service';
import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator'; import { ApiPublicEndpoint } from '../swagger/decorators/swagger-auth.decorator';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { ServiceSuggestion } from './entities/service-suggestion.entity';
@ApiTags('Suggestions') @ApiTags('Suggestions')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('suggestions') @Controller('suggestions')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class SuggestionsController { export class SuggestionsController {
@@ -36,6 +43,7 @@ export class SuggestionsController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(ServiceSuggestion)
@Post() @Post()
create( create(
@Body() createDto: CreateServiceSuggestionDto, @Body() createDto: CreateServiceSuggestionDto,
@@ -46,6 +54,7 @@ export class SuggestionsController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_READ) @Permissions(PermissionCode.SERVICES_READ)
@ApiStandardOkResponse(ServiceSuggestion, { isArray: true })
@Get() @Get()
findAll(@Query() query: FindSuggestionsQueryDto) { findAll(@Query() query: FindSuggestionsQueryDto) {
return this.suggestionsService.findAll(query); return this.suggestionsService.findAll(query);
@@ -53,6 +62,7 @@ export class SuggestionsController {
@Public() @Public()
@ApiPublicEndpoint('Get suggestions for a service') @ApiPublicEndpoint('Get suggestions for a service')
@ApiStandardOkResponse(ServiceSuggestion, { isArray: true })
@Get('for-service/:serviceId') @Get('for-service/:serviceId')
findForService(@Param('serviceId', ParseUUIDPipe) serviceId: string) { findForService(@Param('serviceId', ParseUUIDPipe) serviceId: string) {
return this.suggestionsService.findForService(serviceId); return this.suggestionsService.findForService(serviceId);
@@ -60,6 +70,7 @@ export class SuggestionsController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_READ) @Permissions(PermissionCode.SERVICES_READ)
@ApiStandardOkResponse(ServiceSuggestion)
@Get(':id') @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.suggestionsService.findOne(id); return this.suggestionsService.findOne(id);
@@ -67,6 +78,7 @@ export class SuggestionsController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_WRITE) @Permissions(PermissionCode.SERVICES_WRITE)
@ApiStandardOkResponse(ServiceSuggestion)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -78,6 +90,7 @@ export class SuggestionsController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.SERVICES_DELETE) @Permissions(PermissionCode.SERVICES_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove( remove(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -0,0 +1,125 @@
import { applyDecorators, Type } from '@nestjs/common';
import {
ApiBadRequestResponse,
ApiExtraModels,
ApiForbiddenResponse,
ApiInternalServerErrorResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiTooManyRequestsResponse,
ApiUnauthorizedResponse,
getSchemaPath,
} from '@nestjs/swagger';
import {
ApiErrorResponseDto,
ApiSuccessResponseDto,
} from '../../common/dto/api-response.dto';
export function ApiStandardController() {
return applyDecorators(
ApiExtraModels(ApiSuccessResponseDto, ApiErrorResponseDto),
ApiStandardErrorResponses(),
);
}
export function ApiStandardErrorResponses() {
return applyDecorators(
ApiBadRequestResponse({
description: 'Validation failed or bad request',
type: ApiErrorResponseDto,
}),
ApiUnauthorizedResponse({
description: 'Unauthorized',
type: ApiErrorResponseDto,
}),
ApiForbiddenResponse({
description: 'Forbidden',
type: ApiErrorResponseDto,
}),
ApiNotFoundResponse({
description: 'Resource not found',
type: ApiErrorResponseDto,
}),
ApiInternalServerErrorResponse({
description: 'Internal server error',
type: ApiErrorResponseDto,
}),
);
}
export const ApiStandardOkResponse = <TModel extends Type<unknown>>(
model: TModel,
options?: { isArray?: boolean; nullable?: boolean },
) =>
applyDecorators(
ApiExtraModels(ApiSuccessResponseDto, model),
ApiOkResponse({
description: 'Successful response',
schema: {
allOf: [
{ $ref: getSchemaPath(ApiSuccessResponseDto) },
{
properties: {
data: options?.nullable
? { type: 'null', nullable: true }
: options?.isArray
? {
type: 'array',
items: { $ref: getSchemaPath(model) },
}
: { $ref: getSchemaPath(model) },
},
},
],
},
}),
);
export function ApiStandardEmptyResponse() {
return applyDecorators(
ApiExtraModels(ApiSuccessResponseDto),
ApiOkResponse({
description: 'Successful response with no data',
schema: {
allOf: [
{ $ref: getSchemaPath(ApiSuccessResponseDto) },
{
properties: {
data: { type: 'null', nullable: true },
},
},
],
},
}),
);
}
export function ApiStandardMessageResponse(example = 'Operation completed') {
return applyDecorators(
ApiExtraModels(ApiSuccessResponseDto),
ApiOkResponse({
description: 'Successful response with message only',
schema: {
allOf: [
{ $ref: getSchemaPath(ApiSuccessResponseDto) },
{
properties: {
message: { type: 'string', example },
data: { type: 'null', nullable: true },
},
},
],
},
}),
);
}
export function ApiStandardTooManyRequestsResponse() {
return applyDecorators(
ApiExtraModels(ApiErrorResponseDto),
ApiTooManyRequestsResponse({
description: 'Too many requests',
type: ApiErrorResponseDto,
}),
);
}
+13 -2
View File
@@ -1,12 +1,21 @@
import { INestApplication } from '@nestjs/common'; import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import {
ApiErrorResponseDto,
ApiSuccessResponseDto,
} from '../common/dto/api-response.dto';
export const SWAGGER_JWT_AUTH = 'access-token'; export const SWAGGER_JWT_AUTH = 'access-token';
export function setupSwagger(app: INestApplication): void { export function setupSwagger(app: INestApplication): void {
const config = new DocumentBuilder() const config = new DocumentBuilder()
.setTitle('Grow API') .setTitle('Grow API')
.setDescription('BeautyBook Grow API documentation') .setDescription(
'BeautyBook Grow API documentation.\n\n' +
'All API responses follow a standard envelope:\n' +
'- Success: `{ success: true, data, message?, meta? }`\n' +
'- Error: `{ success: false, statusCode, message, errors?, timestamp, path }`',
)
.setVersion('1.0') .setVersion('1.0')
.addBearerAuth( .addBearerAuth(
{ {
@@ -19,7 +28,9 @@ export function setupSwagger(app: INestApplication): void {
) )
.build(); .build();
const document = SwaggerModule.createDocument(app, config); const document = SwaggerModule.createDocument(app, config, {
extraModels: [ApiSuccessResponseDto, ApiErrorResponseDto],
});
SwaggerModule.setup('docs', app, document, { SwaggerModule.setup('docs', app, document, {
jsonDocumentUrl: 'docs-json', jsonDocumentUrl: 'docs-json',
+12
View File
@@ -23,9 +23,16 @@ import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto'; import { UpdateUserDto } from './dto/update-user.dto';
import { UsersService } from './users.service'; import { UsersService } from './users.service';
import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import {
ApiStandardController,
ApiStandardEmptyResponse,
ApiStandardOkResponse,
} from '../swagger/decorators/swagger-response.decorator';
import { User } from './entities/user.entity';
@ApiTags('Users') @ApiTags('Users')
@ApiBearerAuth(SWAGGER_JWT_AUTH) @ApiBearerAuth(SWAGGER_JWT_AUTH)
@ApiStandardController()
@Controller('users') @Controller('users')
@UseGuards(RolesGuard, PermissionsGuard) @UseGuards(RolesGuard, PermissionsGuard)
export class UsersController { export class UsersController {
@@ -33,6 +40,7 @@ export class UsersController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.USERS_WRITE) @Permissions(PermissionCode.USERS_WRITE)
@ApiStandardOkResponse(User)
@Post() @Post()
create(@Body() createUserDto: CreateUserDto) { create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto); return this.usersService.create(createUserDto);
@@ -40,11 +48,13 @@ export class UsersController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.USERS_READ) @Permissions(PermissionCode.USERS_READ)
@ApiStandardOkResponse(User, { isArray: true })
@Get() @Get()
findAll() { findAll() {
return this.usersService.findAll(); return this.usersService.findAll();
} }
@ApiStandardOkResponse(User)
@Get(':id') @Get(':id')
findOne( findOne(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -56,6 +66,7 @@ export class UsersController {
return this.usersService.findOne(id); return this.usersService.findOne(id);
} }
@ApiStandardOkResponse(User)
@Patch(':id') @Patch(':id')
update( update(
@Param('id', ParseUUIDPipe) id: string, @Param('id', ParseUUIDPipe) id: string,
@@ -70,6 +81,7 @@ export class UsersController {
@Roles(UserRole.ADMIN) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.USERS_DELETE) @Permissions(PermissionCode.USERS_DELETE)
@ApiStandardEmptyResponse()
@Delete(':id') @Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string) { remove(@Param('id', ParseUUIDPipe) id: string) {
return this.usersService.remove(id); return this.usersService.remove(id);