Skip to content

Commit

Permalink
feat: add swagger for some apis (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
lamngockhuong authored Nov 17, 2024
1 parent 2ff7209 commit 4e3dd5c
Show file tree
Hide file tree
Showing 14 changed files with 455 additions and 58 deletions.
28 changes: 25 additions & 3 deletions apps/admin-api/src/api/article/article.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import {
Query,
SerializeOptions,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthOptional, CurrentUser } from '@repo/api';
import { ApiBody, ApiTags } from '@nestjs/swagger';
import { CurrentUser } from '@repo/api';
import { ApiAuth } from '@repo/api/decorators/http.decorators';
import { ArticleService } from './article.service';
import { ArticleListReqDto, ArticleListResDto } from './dto/article-list.dto';
import { ArticleResDto } from './dto/article.dto';
Expand All @@ -22,8 +23,12 @@ export class ArticleController {
constructor(private readonly articleService: ArticleService) {}

@Get()
@AuthOptional()
@SerializeOptions({ type: ArticleListResDto })
@ApiAuth({
summary: 'List Articles',
type: ArticleListResDto,
isAuthOptional: true,
})
async list(@Query() reqDto: ArticleListReqDto): Promise<ArticleListResDto> {
return await this.articleService.list(reqDto);
}
Expand All @@ -40,6 +45,23 @@ export class ArticleController {

@Post()
@SerializeOptions({ type: ArticleResDto })
@ApiAuth({
summary: 'Create Article',
type: ArticleResDto,
})
@ApiBody({
description: 'Article create request',
schema: {
type: 'object',
properties: {
article: {
type: 'object',
$ref: '#/components/schemas/CreateArticleReqDto',
},
},
required: ['article'],
},
})
async create(
@CurrentUser('id') userId: number,
@Body('article') articleData: CreateArticleReqDto,
Expand Down
20 changes: 9 additions & 11 deletions apps/admin-api/src/api/article/dto/article-list.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { NumberFieldOptional, StringFieldOptional } from '@repo/api';
import {
ClassField,
NumberField,
NumberFieldOptional,
StringFieldOptional,
} from '@repo/api';
import { OffsetPaginationDto } from '@repo/api/dto/offset-pagination/offset-pagination.dto';
import { PageOptionsDto } from '@repo/api/dto/offset-pagination/page-options.dto';
import { Expose, Type } from 'class-transformer';
import { ArticleDto } from './article.dto';

export class ArticleListReqDto extends PageOptionsDto {
Expand Down Expand Up @@ -31,17 +34,12 @@ export class ArticleListReqDto extends PageOptionsDto {
}

export class ArticleListResDto {
@ApiProperty({ type: [ArticleDto] })
@Expose()
@Type(() => ArticleDto)
@ClassField(() => ArticleDto, { isArray: true, expose: true })
articles: ArticleDto[];

@ApiProperty()
@Expose()
@NumberField({ expose: true })
articlesCount: number;

@ApiProperty({ type: OffsetPaginationDto })
@Expose()
@Type(() => OffsetPaginationDto)
@ClassField(() => OffsetPaginationDto, { expose: true })
pagination: OffsetPaginationDto;
}
34 changes: 20 additions & 14 deletions apps/admin-api/src/api/article/dto/article.dto.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,47 @@
import { ProfileDto } from '@/api/profile/dto/profile.dto';
import { Expose, Type } from 'class-transformer';
import {
BooleanFieldOptional,
ClassField,
ClassFieldOptional,
DateFieldOptional,
NumberFieldOptional,
StringField,
StringFieldOptional,
} from '@repo/api';

export class ArticleDto {
@Expose()
@StringFieldOptional({ expose: true })
slug?: string;

@Expose()
@StringField({ expose: true })
title: string;

@Expose()
@StringField({ expose: true })
description: string;

@Expose()
@StringField({ expose: true })
body: string;

@Expose()
@StringField({ each: true, expose: true })
tagList: string[];

@Expose()
@DateFieldOptional({ expose: true })
createdAt?: Date;

@Expose()
@DateFieldOptional({ expose: true })
updatedAt?: Date;

@Expose()
@BooleanFieldOptional({ expose: true })
favorited?: boolean;

@Expose()
@NumberFieldOptional({ expose: true })
favoritesCount?: number;

@Expose()
@Type(() => ProfileDto)
@ClassFieldOptional(() => ProfileDto, { expose: true })
author?: ProfileDto;
}

export class ArticleResDto {
@Expose()
@Type(() => ArticleDto)
@ClassField(() => ArticleDto, { expose: true })
article: ArticleDto;
}
26 changes: 21 additions & 5 deletions apps/admin-api/src/api/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import { Body, Controller, Post, SerializeOptions } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Public } from '@repo/api';
import { ApiBody, ApiTags, getSchemaPath } from '@nestjs/swagger';
import { ApiPublic } from '@repo/api/decorators/http.decorators';
import { UserResDto } from '../user/dto/user.dto';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { LoginReqDto } from './dto/login.dto';

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

@Post('users/login')
@Public()
@ApiPublic({
type: UserResDto,
summary: 'Sign in',
})
@ApiBody({
description: 'User login request',
schema: {
type: 'object',
properties: {
user: {
type: 'object',
$ref: getSchemaPath(LoginReqDto),
},
},
required: ['user'],
},
})
@SerializeOptions({ type: UserResDto })
async login(@Body('user') userData: LoginDto): Promise<UserResDto> {
async login(@Body('user') userData: LoginReqDto): Promise<UserResDto> {
return this.authService.login(userData);
}
}
4 changes: 2 additions & 2 deletions apps/admin-api/src/api/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { UserEntity } from '@repo/database-typeorm';
import { verifyPassword } from '@repo/nest-common';
import { Repository } from 'typeorm';
import { UserResDto } from '../user/dto/user.dto';
import { LoginDto } from './dto/login.dto';
import { LoginReqDto } from './dto/login.dto';
import { JwtPayloadType } from './types/jwt-payload.type';

@Injectable()
Expand All @@ -19,7 +19,7 @@ export class AuthService {
private readonly userRepository: Repository<UserEntity>,
) {}

async login(dto: LoginDto): Promise<UserResDto> {
async login(dto: LoginReqDto): Promise<UserResDto> {
const { email, password } = dto;

const user = await this.userRepository.findOne({
Expand Down
2 changes: 1 addition & 1 deletion apps/admin-api/src/api/auth/dto/login.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EmailField, PasswordField } from '@repo/api';

export class LoginDto {
export class LoginReqDto {
@EmailField()
readonly email: string;

Expand Down
13 changes: 6 additions & 7 deletions apps/admin-api/src/api/profile/dto/profile.dto.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { Expose, Type } from 'class-transformer';
import { ClassField, StringField } from '@repo/api';

export class ProfileDto {
@Expose()
@StringField({ expose: true })
username: string;

@Expose()
@StringField({ expose: true })
bio: string;

@Expose()
@StringField({ expose: true })
image: string;

@Expose()
@StringField({ expose: true })
following: boolean;
}

export class ProfileResDto {
@Expose()
@Type(() => ProfileDto)
@ClassField(() => ProfileDto, { expose: true })
profile: ProfileDto;
}
17 changes: 15 additions & 2 deletions apps/admin-api/src/api/profile/profile.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
SerializeOptions,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthOptional, CurrentUser } from '@repo/api';
import { CurrentUser } from '@repo/api';
import { ApiAuth } from '@repo/api/decorators/http.decorators';
import { ProfileResDto } from './dto/profile.dto';
import { ProfileService } from './profile.service';

Expand All @@ -20,8 +21,12 @@ export class ProfileController {
constructor(private readonly profileService: ProfileService) {}

@Get(':username')
@AuthOptional()
@SerializeOptions({ type: ProfileResDto })
@ApiAuth({
summary: 'Get Profile',
type: ProfileResDto,
isAuthOptional: true,
})
getProfile(
@CurrentUser('id') userId: number,
@Param('username') username: string,
Expand All @@ -31,6 +36,10 @@ export class ProfileController {

@Post(':username/follow')
@SerializeOptions({ type: ProfileResDto })
@ApiAuth({
summary: 'Follow User',
type: ProfileResDto,
})
follow(
@CurrentUser('id') userId: number,
@Param('username') username: string,
Expand All @@ -40,6 +49,10 @@ export class ProfileController {

@Delete(':username/follow')
@SerializeOptions({ type: ProfileResDto })
@ApiAuth({
summary: 'Unfollow User',
type: ProfileResDto,
})
unfollow(
@CurrentUser('id') userId: number,
@Param('username') username: string,
Expand Down
15 changes: 7 additions & 8 deletions apps/admin-api/src/api/user/dto/user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import { Expose, Type } from 'class-transformer';
import { ClassField, EmailField, StringField } from '@repo/api';

export class UserDto {
@Expose()
@EmailField({ expose: true })
email: string;

@Expose()
@StringField({ expose: true })
token: string;

@Expose()
@StringField({ expose: true })
username: string;

@Expose()
@StringField({ expose: true })
bio: string;

@Expose()
@StringField({ expose: true })
image: string;
}

export class UserResDto {
@Expose()
@Type(() => UserDto)
@ClassField(() => UserDto, { expose: true })
user: UserDto;
}
44 changes: 41 additions & 3 deletions apps/admin-api/src/api/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
Put,
SerializeOptions,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { CurrentUser, Public } from '@repo/api';
import { ApiBody, ApiTags, getSchemaPath } from '@nestjs/swagger';
import { CurrentUser } from '@repo/api';
import { ApiAuth, ApiPublic } from '@repo/api/decorators/http.decorators';
import { CreateUserReqDto } from './dto/create-user.dto';
import { UpdateUserReqDto } from './dto/update-user.dto';
import { UserResDto } from './dto/user.dto';
Expand All @@ -20,21 +21,58 @@ export class UserController {

@Get('user')
@SerializeOptions({ type: UserResDto })
@ApiAuth({
summary: 'Get Current User',
type: UserResDto,
})
getCurrent(
@CurrentUser() currentUser: { id: number; token: string },
): Promise<UserResDto> {
return this.userService.get(currentUser);
}

@Post('users')
@Public()
@ApiPublic({
type: UserResDto,
summary: 'Registration',
})
@ApiBody({
description: 'User register request',
schema: {
type: 'object',
properties: {
user: {
type: 'object',
$ref: getSchemaPath(CreateUserReqDto),
},
},
required: ['user'],
},
})
@SerializeOptions({ type: UserResDto })
async create(@Body('user') userData: CreateUserReqDto): Promise<UserResDto> {
return this.userService.create(userData);
}

@Put('user')
@SerializeOptions({ type: UserResDto })
@ApiAuth({
summary: 'Update User',
type: UserResDto,
})
@ApiBody({
description: 'User update request',
schema: {
type: 'object',
properties: {
user: {
type: 'object',
$ref: getSchemaPath(UpdateUserReqDto),
},
},
required: ['user'],
},
})
async update(
@CurrentUser('id') userId: number,
@Body('user') userData: UpdateUserReqDto,
Expand Down
Loading

0 comments on commit 4e3dd5c

Please sign in to comment.