Skip to content

Commit

Permalink
feat(be): implement GraphQL Exceptions (#1267)
Browse files Browse the repository at this point in the history
* feat: create transport exceptions for GraphQL Request

* feat: add exception conversion onto the transport level

* feat: add optional exception message setting argument

* refactor: add default message to InternalServerGraphQLError

* refactor: replace error throwing logic in controllers by using convert2~ methods

* refactor: change exception name

* feat: add apollo server error formatter

HTTPException의 상태 코드를 GQL 에러 코드로 변환시켜줌

* fix: make resolvers throw HTTP Exceptions

* fix: delete status property

* refactor: refactor apollo-error-formatter

* fix: change Gql Error to HTTP Error

* refactor: delete unused class method

* refactor: delete unused exceptions

- Custom GraphQL Errors 삭제
- 파일 이름 변경 (graphql-error.exception -> graphql-error-code)

---------

Co-authored-by: Jaehyeon Kim <[email protected]>
  • Loading branch information
2 people authored and cho-to committed Feb 19, 2024
1 parent a84e41d commit 2345290
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 116 deletions.
4 changes: 3 additions & 1 deletion backend/apps/admin/src/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
GroupLeaderGuard
} from '@libs/auth'
import { CacheConfigService } from '@libs/cache'
import { apolloErrorFormatter } from '@libs/exception'
import { pinoLoggerModuleOption } from '@libs/logger'
import { PrismaModule } from '@libs/prisma'
import { AdminController } from './admin.controller'
Expand All @@ -34,7 +35,8 @@ import { UserModule } from './user/user.module'
driver: ApolloDriver,
autoSchemaFile: 'schema.gql',
sortSchema: true,
introspection: true
introspection: true,
formatError: apolloErrorFormatter
}),
CacheModule.registerAsync({
isGlobal: true,
Expand Down
38 changes: 19 additions & 19 deletions backend/apps/admin/src/contest/contest.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {
BadRequestException,
InternalServerErrorException,
Logger,
NotFoundException,
ParseBoolPipe,
UnprocessableEntityException
ParseBoolPipe
} from '@nestjs/common'
import { Args, Context, Int, Mutation, Query, Resolver } from '@nestjs/graphql'
import { AuthenticatedRequest, UseRolesGuard } from '@libs/auth'
Expand Down Expand Up @@ -61,10 +58,11 @@ export class ContestResolver {
input
)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
} else if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof EntityNotExistException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -79,10 +77,11 @@ export class ContestResolver {
try {
return await this.contestService.updateContest(groupId, input)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
} else if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
if (
error instanceof EntityNotExistException ||
error instanceof UnprocessableDataException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -98,7 +97,7 @@ export class ContestResolver {
return await this.contestService.deleteContest(groupId, contestId)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -122,10 +121,11 @@ export class ContestResolver {
contestId
)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
} else if (error instanceof ConflictFoundException) {
throw new BadRequestException(error.message)
if (
error instanceof EntityNotExistException ||
error instanceof ConflictFoundException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -145,7 +145,7 @@ export class ContestResolver {
)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -166,7 +166,7 @@ export class ContestResolver {
)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down
22 changes: 9 additions & 13 deletions backend/apps/admin/src/group/group.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
ConflictException,
ForbiddenException,
InternalServerErrorException,
Logger
} from '@nestjs/common'
import { InternalServerErrorException, Logger } from '@nestjs/common'
import { Args, Int, Query, Mutation, Resolver, Context } from '@nestjs/graphql'
import { Group } from '@generated'
import { Role } from '@prisma/client'
Expand Down Expand Up @@ -34,7 +29,7 @@ export class GroupResolver {
return await this.groupService.createGroup(input, req.user.id)
} catch (error) {
if (error instanceof DuplicateFoundException) {
throw new ConflictException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down Expand Up @@ -66,10 +61,11 @@ export class GroupResolver {
try {
return await this.groupService.updateGroup(id, input)
} catch (error) {
if (error instanceof DuplicateFoundException) {
throw new ConflictException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
if (
error instanceof DuplicateFoundException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -85,7 +81,7 @@ export class GroupResolver {
return await this.groupService.deleteGroup(id, req.user)
} catch (error) {
if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -100,7 +96,7 @@ export class GroupResolver {
return await this.groupService.issueInvitation(id)
} catch (error) {
if (error instanceof ConflictFoundException) {
throw new ConflictException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down
51 changes: 27 additions & 24 deletions backend/apps/admin/src/problem/problem.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {
ConflictException,
ForbiddenException,
InternalServerErrorException,
Logger,
NotFoundException,
Expand Down Expand Up @@ -54,7 +52,7 @@ export class ProblemResolver {
)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
throw error.convert2HTTPException()
} else if (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.code === 'P2003'
Expand Down Expand Up @@ -86,7 +84,7 @@ export class ProblemResolver {
)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down Expand Up @@ -146,16 +144,17 @@ export class ProblemResolver {
try {
return await this.problemService.updateProblem(input, groupId)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof ConflictFoundException
) {
throw error.convert2HTTPException()
} else if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.name == 'NotFoundError') {
throw new NotFoundException(error.message)
} else if (error.code === 'P2003') {
throw new UnprocessableEntityException(error.message)
}
} else if (error instanceof ConflictFoundException) {
throw new ConflictException(error.message)
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down Expand Up @@ -199,10 +198,11 @@ export class ProblemResolver {
try {
return this.problemService.getWorkbookProblems(groupId, workbookId)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
} else if (error.code == 'P2025') {
throw new EntityNotExistException(error.message)
}
Expand Down Expand Up @@ -230,10 +230,11 @@ export class ProblemResolver {
orders
)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
} else if (error.code == 'P2025') {
throw new EntityNotExistException(error.message)
}
Expand All @@ -255,10 +256,11 @@ export class ProblemResolver {
try {
return this.problemService.getContestProblems(groupId, contestId)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
} else if (error.code == 'P2025') {
throw new EntityNotExistException(error.message)
}
Expand All @@ -285,10 +287,11 @@ export class ProblemResolver {
orders
)
} catch (error) {
if (error instanceof UnprocessableDataException) {
throw new UnprocessableEntityException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
if (
error instanceof UnprocessableDataException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
} else if (error.code == 'P2025') {
throw new EntityNotExistException(error.message)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
Controller,
Get,
Logger,
NotFoundException,
InternalServerErrorException,
Query,
BadRequestException
Expand Down Expand Up @@ -39,7 +38,7 @@ export class AnnouncementController {
}
} catch (error) {
if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand Down
8 changes: 4 additions & 4 deletions backend/apps/client/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class AuthController {
this.setJwtResponse(res, jwtTokens)
} catch (error) {
if (error instanceof UnidentifiedException) {
throw new UnauthorizedException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException('Login failed')
Expand Down Expand Up @@ -87,7 +87,7 @@ export class AuthController {
this.setJwtResponse(res, newJwtTokens)
} catch (error) {
if (error instanceof InvalidJwtTokenException) {
throw new UnauthorizedException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException('Failed to reissue tokens')
Expand All @@ -114,7 +114,7 @@ export class AuthController {
return await this.authService.githubLogin(res, githubUser)
} catch (error) {
if (error instanceof UnidentifiedException) {
throw new UnauthorizedException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException('Login failed')
Expand Down Expand Up @@ -142,7 +142,7 @@ export class AuthController {
return await this.authService.kakaoLogin(res, kakaoUser)
} catch (error) {
if (error instanceof UnidentifiedException) {
throw new UnauthorizedException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException('Login failed')
Expand Down
3 changes: 1 addition & 2 deletions backend/apps/client/src/contest/contest.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
Get,
Query,
Logger,
ConflictException,
DefaultValuePipe
} from '@nestjs/common'
import { Prisma } from '@prisma/client'
Expand Down Expand Up @@ -119,7 +118,7 @@ export class ContestController {
) {
throw new NotFoundException(error.message)
} else if (error instanceof ConflictFoundException) {
throw new ConflictException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException(error.message)
Expand Down
15 changes: 7 additions & 8 deletions backend/apps/client/src/group/group.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {
ConflictException,
Controller,
DefaultValuePipe,
Delete,
ForbiddenException,
Get,
InternalServerErrorException,
Logger,
Expand Down Expand Up @@ -95,7 +93,7 @@ export class GroupController {
) {
throw new NotFoundException('Invalid invitation')
} else if (error instanceof EntityNotExistException) {
throw new NotFoundException(error.message)
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -120,10 +118,11 @@ export class GroupController {
error.name === 'NotFoundError'
) {
throw new NotFoundException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw new ForbiddenException(error.message)
} else if (error instanceof ConflictFoundException) {
throw new ConflictException(error.message)
} else if (
error instanceof ForbiddenAccessException ||
error instanceof ConflictFoundException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -140,7 +139,7 @@ export class GroupController {
return await this.groupService.leaveGroup(req.user.id, groupId)
} catch (error) {
if (error instanceof ConflictFoundException) {
throw new ConflictException(error.message)
throw error.convert2HTTPException()
}

this.logger.error(error)
Expand Down
Loading

0 comments on commit 2345290

Please sign in to comment.