Skip to content

Commit

Permalink
Fix: gql 셋팅 및 마이그레이션 (#47)
Browse files Browse the repository at this point in the history
* Fix: gcl 셋팅 및 swagger 이중 참조 삭제
  • Loading branch information
minchodang authored Dec 5, 2024
1 parent 8baf7e4 commit 00f6078
Show file tree
Hide file tree
Showing 44 changed files with 942 additions and 967 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,25 @@
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"@apollo/server": "^4.11.2",
"@aws-sdk/client-dynamodb": "^3.540.0",
"@aws-sdk/client-ses": "^3.549.0",
"@aws-sdk/lib-dynamodb": "^3.549.0",
"@nestjs/apollo": "^12.2.1",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.0.0",
"@nestjs/graphql": "^12.2.1",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.3.0",
"@supabase/supabase-js": "^2.45.3",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"commander": "^12.1.0",
"cookie-parser": "^1.4.6",
"graphql": "^16.9.0",
"mysql2": "^3.9.1",
"passport": "^0.7.0",
"passport-google-oauth20": "^2.0.0",
Expand All @@ -52,7 +55,6 @@
"pm2": "^5.3.1",
"reflect-metadata": "^0.1.14",
"rxjs": "^7.8.1",
"swagger-ui-express": "^5.0.0",
"typeorm": "^0.3.20",
"uuid": "^9.0.1"
},
Expand Down
813 changes: 758 additions & 55 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { ConfigModule } from '@nestjs/config';
import { HealthCheckController } from './modules/health-check/health-check.controller';
import { DynamoDBModule } from './database/dynamodb/dynamodb.module';
import { UserModule } from './modules/user/user.module';
import { AuthModule } from './modules/auth/auth.module';
import { TestModule } from './modules/test/test.module';
import { join } from 'path';

@Module({
imports: [DynamoDBModule, UserModule, AuthModule, TestModule],
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true,
}),
DynamoDBModule,
UserModule,
AuthModule,
TestModule
],
controllers: [HealthCheckController],
providers: [],
})
Expand Down
8 changes: 0 additions & 8 deletions src/core/errors/unauthorized-error.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';

export class UnauthorizedError {
@ApiProperty({
example: ['No token', 'Invalid token', 'Token expired'],
})
message: string[];

@ApiProperty({
example: 'Unauthorized',
})
error: 'Unauthorized';
}
47 changes: 5 additions & 42 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,16 @@
import 'dotenv/config';
import { NestFactory, Reflector } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import * as cookieParser from 'cookie-parser';
import { BaseExceptionFilter } from 'src/core/filters/base-exception-filter';
import { writeFileSync } from 'fs';
import { join } from 'path';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
// set CORS
app.useGlobalPipes(new ValidationPipe());
app.enableCors({
origin: true,
origin: process.env.CORS_ORIGIN,
credentials: true,
exposedHeaders: ['Authorization'],
});
// set swagger module
const config = new DocumentBuilder()
.setTitle('Meta Test API')
.setDescription('The Meta Test API')
.setVersion('1.0.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
const swaggerJson = JSON.stringify(document, null, 2);
writeFileSync(join(process.cwd(), 'swagger-spec.json'), swaggerJson);
SwaggerModule.setup('api', app, document);

app.useGlobalPipes(
new ValidationPipe({
transform: true,
}),
);

app.useGlobalFilters(new BaseExceptionFilter());

app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
app.use(cookieParser());
// set port
const port =
process.env.NODE_ENV === 'dev'
? 8000
: process.env.NODE_ENV === 'production'
? 8080
: 3000;

console.log('server start at', port);

const port = process.env.PORT || 3000;
await app.listen(port);
}
bootstrap();
185 changes: 2 additions & 183 deletions src/modules/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,66 +11,28 @@ import {
Res,
UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { KakaoAuthGuard } from 'src/auth/guard/kakao.auth.guard';
import { AuthService } from './auth.service';
import { CreateTokenRequestDto } from './dto/create-token-request.dto';
import { CreateTokenResponseDto } from './dto/create-token-response.dto';
import { RefreshTokenRequestDto } from './dto/refresh-token-request.dto';
import { RefreshTokenResponseDto } from './dto/refresh-token-response.dto';
import { SocialLoginRequestDto } from './dto/social-login-request.dto';
import { GoogleAuthGuard } from 'src/auth/guard/google.auth.guard';
import { ResetPasswordRequestDto } from './dto/reset-password-request.dto';
import { EmailVerificationRequestDto } from './dto/email-verification-request.dto';
import { UpdateEmailVerificationRequestDto } from './dto/update-email-verification-request.dto';
import { UserType } from 'src/types/userType';
import { CreateTokenRequestBodyError } from './error/create-token-error';
import { RefreshTokenRequestBodyError } from './error/refresh-token-error';
import { ResetPasswordRequestBodyError } from './error/reset-password-error';
import { EmailVerificationRequestBodyError } from './error/email-verification-error';
import { UpdateEmailVerificationRequestBodyError } from './error/update-email-verification-error';
import { EmailVerificationResponseDto } from './dto/email-verification-response.dto';

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

@Post('token')
@ApiOperation({ summary: '로그인', description: '토큰 발급' })
@ApiResponse({
status: 201,
description: 'Created',
type: CreateTokenResponseDto,
})
@ApiResponse({
status: 400,
description: 'Bad request',
type: CreateTokenRequestBodyError,
})
@ApiResponse({
status: 401,
description: 'Unauthorized',
content: {
'application/json': {
example: {
message: 'User not found or password does not match',
error: 'Unauthorized',
},
},
},
})
@ApiResponse({
status: 500,
description: 'Internal Server Error',
})
@HttpCode(HttpStatus.CREATED)
async createToken(
@Body() createTokenInfoDto: CreateTokenRequestDto,
@Res() res: Response,
) {
//NOTE: 이 API가 호출되는 유저는 일반 유저이므로 userType = NORMAL
const tokens = await this.authService.create(
createTokenInfoDto,
UserType.NORMAL,
Expand All @@ -86,36 +48,6 @@ export class AuthController {
}

@Post('token/refresh')
@ApiOperation({
summary: '토큰 재발급',
description: '토큰 재발급',
})
@ApiResponse({
status: 201,
description: 'Created',
type: RefreshTokenResponseDto,
})
@ApiResponse({
status: 400,
description: 'Bad request',
type: RefreshTokenRequestBodyError,
})
@ApiResponse({
status: 401,
description: 'Unauthorized',
content: {
'application/json': {
example: {
message: 'Invalid token',
error: 'Unauthorized',
},
},
},
})
@ApiResponse({
status: 500,
description: 'Internal Server Error',
})
@HttpCode(HttpStatus.CREATED)
async refreshToken(
@Body() refreshTokenInfoDto: RefreshTokenRequestDto,
Expand All @@ -132,14 +64,6 @@ export class AuthController {
res.status(HttpStatus.CREATED).send();
}

@ApiOperation({
summary: '카카오 소셜로그인',
description: '기가입 유저는 로그인, 신규 유저는 회원가입 진행',
})
@ApiResponse({
status: 201,
description: 'Created',
})
@UseGuards(KakaoAuthGuard)
@Get('login/kakao')
async loginWithKakao(
Expand All @@ -158,14 +82,6 @@ export class AuthController {
res.status(HttpStatus.CREATED).send();
}

@ApiOperation({
summary: '구글 소셜로그인',
description: '기가입 유저는 로그인, 신규 유저는 회원가입 진행',
})
@ApiResponse({
status: 201,
description: 'Created',
})
@UseGuards(GoogleAuthGuard)
@Get('login/google')
async loginWithGoogle(
Expand All @@ -185,61 +101,13 @@ export class AuthController {
}

@Patch('password')
@ApiOperation({
summary: '비밀번호 초기화',
description: '비밀번호 변경하고 이메일로 전송합니다.',
})
@ApiResponse({
status: 200,
description: 'OK',
})
@ApiResponse({
status: 400,
description: 'Bad request',
type: ResetPasswordRequestBodyError,
})
@ApiResponse({
status: 404,
description: 'Not Found',
content: {
'application/json': {
example: {
message: 'User does not exist',
error: 'Not Found',
},
},
},
})
@ApiResponse({
status: 500,
description: 'Internal Server Error',
})
@HttpCode(HttpStatus.OK)
async updateUserPassword(@Body() body: ResetPasswordRequestDto) {
const email = body.email;
//NOTE: reset password는 일반유저만 가능(소셜로그인 유저 X)
return await this.authService.resetUserPassword(email, UserType.NORMAL);
}

@Post('email-verification')
@ApiOperation({
summary: '이메일 인증 요청',
description: '이메일 인증 요청 메일을 발송',
})
@ApiResponse({
status: 201,
description: 'Created',
type: EmailVerificationResponseDto,
})
@ApiResponse({
status: 400,
description: 'Bad request',
type: EmailVerificationRequestBodyError,
})
@ApiResponse({
status: 500,
description: 'Internal Server Error',
})
@HttpCode(HttpStatus.CREATED)
async createEmailVerificaiton(
@Body() body: EmailVerificationRequestDto,
Expand All @@ -251,62 +119,13 @@ export class AuthController {
}

@Patch('email-verification')
@ApiOperation({
summary: '이메일 인증 검증',
description: '임시토큰으로 이메일 인증을 검증',
})
@ApiResponse({
status: 200,
description: 'OK',
})
@ApiResponse({
status: 400,
description: 'Bad request',
type: UpdateEmailVerificationRequestBodyError,
})
@ApiResponse({
status: 401,
description: 'Unauthorized',
content: {
'application/json': {
examples: {
UpdateEmailVerificationUnauthorizedError: {
value: {
message: 'Invalid request_id',
error: 'Unauthorized',
},
description: 'request_id가 유효하지 않음',
},
UpdateEmailVerificationUnauthorizedError2: {
value: {
message: 'Invalid code',
error: 'Unauthorized',
},
description: 'code가 유효하지 않음',
},
UpdateEmailVerificationUnauthorizedError3: {
value: {
message: 'Expired request_id',
error: 'Unauthorized',
},
description: 'request_id가 만료됨',
},
},
},
},
})
@ApiResponse({
status: 500,
description: 'Internal Server Error',
})
@HttpCode(HttpStatus.OK)
async updateEmailVerificaiton(
@Body() body: UpdateEmailVerificationRequestDto,
@Res({ passthrough: true }) res: Response,
) {
const id = body.request_id;
const code = body.code;
await this.authService.updateEmailVerificaiton(id, code);
const { request_id, code } = body;
await this.authService.updateEmailVerificaiton(request_id, code);
res.status(HttpStatus.OK).send();
}
}
Loading

0 comments on commit 00f6078

Please sign in to comment.