Skip to content

Commit

Permalink
add Swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
AbdelrahmanBayoumi committed Jul 22, 2023
1 parent 93a71cd commit 9a66dcb
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 12 deletions.
4 changes: 3 additions & 1 deletion src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Controller, Get } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';

@Controller()
export class AppController {
@ApiOkResponse({ description: 'Health check endpoint' })
@Get('/health-check')
healthCheck(): { status: string } {
return { status: 'ok' };
}

// return a plain text string as a response to the GET request to the root path
@ApiOkResponse({ description: 'Hello World endpoint' })
@Get()
getHello(): string {
return 'Hello World!';
Expand Down
4 changes: 4 additions & 0 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import { GetUser } from './decorator';
import { User } from '@prisma/client';
import { AccessTokenGuard, RefreshTokenGuard } from './guard';
import { Tokens } from './types';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';

@ApiTags('auth')
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}

@ApiOkResponse({ description: 'succes signup endpoint' })
@Post('signup')
@HttpCode(HttpStatus.CREATED)
signup(@Body() dto: SignUpDto): Promise<Tokens> {
Expand All @@ -31,6 +34,7 @@ export class AuthController {
return this.authService.login(dto);
}

@ApiOkResponse({ description: 'check token endpoint' })
@Get('check')
@UseGuards(AccessTokenGuard)
checkToken(@GetUser() user: User) {
Expand Down
2 changes: 2 additions & 0 deletions src/auth/dto/email.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { IsEmail, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class EmailDto {
@ApiProperty({ example: '[email protected]', description: 'User email' })
@IsEmail()
@IsNotEmpty()
email: string;
Expand Down
7 changes: 7 additions & 0 deletions src/auth/dto/login.dto.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { IsEmail, IsNotEmpty, IsString, Length } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class LoginDto {
@ApiProperty({ example: '[email protected]', description: 'User email' })
@IsEmail()
@IsNotEmpty()
email: string;

@ApiProperty({
example: 'password',
description: 'User password',
minLength: 6,
})
@IsString()
@IsNotEmpty()
@Length(6)
Expand Down
12 changes: 12 additions & 0 deletions src/auth/dto/signup.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,32 @@ import {
IsString,
MinLength,
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class SignUpDto {
@ApiProperty({ example: '[email protected]', description: 'User email' })
@IsEmail()
@IsNotEmpty()
email: string;

@ApiProperty({ example: 'John Doe', description: 'User full name' })
@IsString()
@IsNotEmpty()
fullName: string;

@ApiProperty({
example: '2000-01-01',
description: 'User birthday in ISO 8601 format',
})
@IsISO8601()
@IsNotEmpty()
birthday: string;

@ApiProperty({
example: 'password',
description: 'User password',
minLength: 6,
})
@IsString()
@IsNotEmpty()
@MinLength(6)
Expand Down
2 changes: 2 additions & 0 deletions src/birthday/birthday.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import { AccessTokenGuard, VerificationGuard } from '../auth/guard';
import { GetUser } from '../auth/decorator';
import { CreateBirthdayDto, EditBirthdayDto } from './dto';
import { User } from '@prisma/client';
import { ApiTags } from '@nestjs/swagger';

@UseGuards(AccessTokenGuard, VerificationGuard)
@ApiTags('birthday')
@Controller('birthday')
export class BirthdayController {
constructor(private birthdayService: BirthdayService) {}
Expand Down
5 changes: 5 additions & 0 deletions src/birthday/dto/create-birthday.dto.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, IsString, IsISO8601, IsNotEmpty } from 'class-validator';

export class CreateBirthdayDto {
@ApiProperty({ example: 'john doe', description: 'full name' })
@IsString()
@IsNotEmpty()
name: string;

@ApiProperty({ example: '2000-01-01', description: 'birthday' })
@IsISO8601()
@IsNotEmpty()
birthday: string;

@ApiProperty({ example: 'father', description: 'relationship' })
@IsString()
@IsOptional()
relationship?: string;

@ApiProperty({ example: 'notes', description: 'notes' })
@IsString()
@IsOptional()
notes?: string;
Expand Down
10 changes: 10 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { Logger } from 'nestjs-pino';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
// cors: true = allow all the request from any domain
Expand All @@ -10,6 +11,15 @@ async function bootstrap() {
bufferLogs: true,
});

const config = new DocumentBuilder()
.addBearerAuth()
.setTitle('Birthday Database API')
.setDescription('Birthday Database API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

app.useLogger(app.get(Logger));

// [whitelist: true] = remove all the properties that are not defined in the DTO
Expand Down
3 changes: 3 additions & 0 deletions src/user/dto/change-password.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class ChangePasswordDto {
@ApiProperty({ example: 'password', description: 'current password' })
@IsString()
currentPassword: string;

@ApiProperty({ example: 'newPassword', description: 'new password' })
@IsString()
@MinLength(6)
newPassword: string;
Expand Down
4 changes: 3 additions & 1 deletion src/user/dto/edit-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { IsOptional, IsString, IsISO8601, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class EditUserDto {
@IsString()
@ApiProperty({ example: 'john doe', description: 'full name' })
@IsOptional()
@IsNotEmpty()
fullName?: string;

@ApiProperty({ example: '2000-01-01', description: 'birthday' })
@IsISO8601()
@IsOptional()
birthday?: string;
Expand Down
21 changes: 11 additions & 10 deletions src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { GetUser } from '../auth/decorator';
import { ChangePasswordDto, EditUserDto } from './dto';
import { UserService } from './user.service';
import { User } from '@prisma/client';
import { ApiTags } from '@nestjs/swagger';

@UseGuards(AccessTokenGuard)
@ApiTags('users')
@Controller('users')
export class UserController {
constructor(private userService: UserService) {}
Expand All @@ -37,27 +39,26 @@ export class UserController {
return this.userService.editUser(userId, dto);
}

@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
async deleteUser(
@Patch(':id/change-password')
async changePassword(
@Body() changePasswordDto: ChangePasswordDto,
@GetUser() user: User,
@Param('id', ParseIntPipe) userId: number,
) {
this.checkIfUserIsAuthorized(user, userId);
await this.userService.deleteUser(userId);
return;
return this.userService.changePassword(userId, changePasswordDto);
}

@Patch(':id/change-password')
async changePassword(
@Body() changePasswordDto: ChangePasswordDto,
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
async deleteUser(
@GetUser() user: User,
@Param('id', ParseIntPipe) userId: number,
) {
this.checkIfUserIsAuthorized(user, userId);
return this.userService.changePassword(userId, changePasswordDto);
await this.userService.deleteUser(userId);
return;
}

/**
* Check if user is authorized to perform action
* @param user user from access token
Expand Down

0 comments on commit 9a66dcb

Please sign in to comment.