Swagger 설정, Google Cloud MySQL 설정을 완료했으니

 

1. 구글 로그인 사용을 위해 아래 노드 패키지를 설치해준다.

 

1
2
3
# passport 설치
$ npm install @nestjs/passport
$ npm install passport-google-oauth20
cs

 

2. src 하위에 auth 폴더를 만들어준다.

 

 auth 폴더 하위에 cotroller, service, module 을 만들어준다.

 

2.1. auth.contoller.ts 생성

// auth.controller.ts
import { Controller, Get, UseGuards, Req } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';

@ApiTags('auth API')
@Controller('auth')
export class AuthController {

  @ApiOperation({ summary: 'google login auth' })
  @ApiResponse({ status: 200, description: 'google login auth' })
  @Get('google')
  @UseGuards(AuthGuard('google'))
  googleLogin() {
  }

  @ApiOperation({ summary: 'google login auth callback' })
  @ApiResponse({ status: 200, description: 'google login auth callback' })
  @Get('google/callback')
  @UseGuards(AuthGuard('google'))
  googleLoginCallback(@Req() req) {
    return {
      user: req.user,
    };
  }
}

 

2.2. auth.service.ts 생성

// auth.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AuthService {
}

2.3. auth.module.ts 생성

import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from 'src/user/user.entity';
import { GoogleStrategy } from 'src/strategies/google.strategy';
import { AuthController } from './auth.contoller';
@Module({
  // eslint-disable-next-line prettier/prettier
  imports: [
    PassportModule.register({ defaultStrategy: 'google' }),
    TypeOrmModule.forFeature([User]),
  ],
  providers: [AuthService, GoogleStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

 

 

2.4. Passport의 Google 전략 사용을 위해 src/strategies/google.strategy.ts 파일을 생성 후 작성해준다.

// google.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { Strategy } from 'passport-google-oauth20';
import { User } from 'src/user/user.entity';
import { Repository } from 'typeorm';

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {
    super({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: 'http://localhost:3000/auth/google/callback',
      scope: ['email', 'profile'],
    });
  }

  // eslint-disable-next-line @typescript-eslint/ban-types
  async validate(accessToken: string, refreshToken: string, profile: any, done: Function): Promise<any> {
    const { name, emails, photos } = profile;

    const user = await this.userRepository.findOne({ where: { email: emails[0].value } });

    if (user) {
      return done(null, user);
    }

    const newUser = new User();
    newUser.email = emails[0].value;
    newUser.firstName = name.givenName;
    newUser.lastName = name.familyName;
    newUser.picture = photos[0].value;

    const result = await this.userRepository.save(newUser);

    return done(null, result);
  }
}

 

2.5.  User 정보 데이터 바인딩 및 저장을 위해 src/user/user.entity.ts 파일을 생성해준다.

// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, OneToMany, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ nullable: true })
  picture: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}

 

2.6 서버를 실행 후 아래 주소로 접속한다.

 

http://localhost:3000/auth/google

 

구글 계정 목록이 나타나고 로그인 시 계정에 대한 정보를 확인할 수 있다.

 

이제 해당 데이터를 가지고 service 단에서 User 정보를 DB에 저장할수 있고

필요한 로직을 추가할수 있다.

 

기본적인 셋팅이 완료되면 localhost로 갖고있는것보단

Google App Engine을 활용해 NestJS 프로젝트를 바로 올려 DEV(개발용)으로 사용할수 있다.

해당 과정은 이지하므로 포스팅 작성하는것을 생략하려고 한다.

 

 

위 이미지를 통해 DEV로 올라간 NestJS 프로젝트 를 확인할수 있다.

 

마지막으로 github 코드를 첨부한다.

 

https://github.com/shlee0882/nestjs-study

 

GitHub - shlee0882/nestjs-study: :cat: Nest JS 스터디

:cat: Nest JS 스터디. Contribute to shlee0882/nestjs-study development by creating an account on GitHub.

github.com

 

 

이번 토이 프로젝트는 NetJS에 Google Cloud MySQL , Google App Engine을 붙여사용했는데

개발에 대한 편의성은 높아졌지만 서비스 이용에 대한 비용부담이 커졌다.

 

15일 정도 혼자 사용했는데 7만원이라니...  굉장한 과금이다...

개발비용을 고려하지 못한 내 잘못이긴한데  흙수저인 나에게 부담이 되긴하다.

 

 

'전체 > NestJS' 카테고리의 다른 글

NestJs 토이 프로젝트 구성해보기 - 1  (2) 2023.07.16

NestJS는 백엔드 서버 사이드 애플리케이션을 구축하기 위한 프레임워크이다.

고양이 그림이 귀여워서 공부해보았다.

 

 

 

1. nestjs/cli 를 전역으로 설치해준다.

 

1
2
3
# nest 프로젝트 설치
$ npm i -g @nestjs/cli
$ nest new nestjs-study
cs

 

2. 적절한 위치에서 nestjs 프로젝트를 생성해준다.

 

3. vsc 를 실행하면 다음과 같은 구조가 보일것이다.

NestJS는 모듈, 서비스, 컨트롤러라는 개념을 사용해 코드를 구조화한다.

 

4. 서버를 실행하면 Hello World 가 나오게 된다.

5. 모듈, 서비스, 컨트롤러라는 개념을 적용해 확장 구현해보자.

 

아래 cmd를 이용해 task subject에 대한 service, controller, module을 생성해준다.

 

 

1
2
3
4
# controller, service, module 생성
$ nest generate controller task
$ nest generate service task
$ nest generate module task
cs

src 하위로 디렉토리가 생성된다. 

 

6. TypeORM을 사용하여 Google Cloud SQL의 MySQL 데이터베이스에 연결하기

 

1
2
3
4
5
6
7
8
9
10
11
# type orm mysql 설치
$ npm install --save @nestjs/typeorm typeorm mysql
 
# 환경변수 설정파일 
$ npm install dotenv
 
# config env파일 불러오기 위한 설치
$ npm install @nestjs/config
 
# swagger 설치
$ npm install --save @nestjs/swagger swagger-ui-express
cs

 

필요한 노드 패키지를 설치해준다.

.env 파일에 민감한 정보를 작성해주고 저장한다.

 

 

6-1. app.module.ts 파일을 수정해준다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TaskModule } from './task/task.module';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, // makes the config global
      envFilePath: '.env', // point to .env in root directory
    }),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: process.env.DB_HOST,
      port: +process.env.DB_PORT,
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_DATABASE,
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
      extra: process.env.INSTANCE_CONNECTION_NAME && process.env.NODE_ENV === 'dev' 
      ? { socketPath: `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}` } 
      : undefined,
    }),
    TaskModule,
  ],
})
export class AppModule {}

 

6-2. task.entity.ts 파일을 만든다.

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('tasks') // Specifies the name of the table in the database
export class Task {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  description: string;
}

 

6-3. task.controller.ts 파일을 수정해준다.

import { Controller, Get, Post, Body } from '@nestjs/common';
import { TaskService } from './task.service';
import { Task } from './task.entity';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';

@ApiTags('task API')
@Controller('tasks')
export class TaskController {
  constructor(private taskService: TaskService) {}

  @ApiOperation({ summary: 'Retrieve a list of task.' })
  @ApiResponse({ status: 200, description: 'List of task.' })
  @Get()
  findAll(): Promise<Task[]> {
    return this.taskService.findAll();
  }

  @ApiOperation({ summary: 'Create an task.' })
  @ApiResponse({ status: 201, description: 'The task has been successfully created.' })
  @Post()
  create(@Body() task: Task): Promise<Task> {
    return this.taskService.create(task);
  }
}

 

6-4. task.service.ts 파일을 수정해준다.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Task } from './task.entity';

@Injectable()
export class TaskService {
  constructor(
    @InjectRepository(Task)
    private taskRepository: Repository<Task>,
  ) {}

  findAll(): Promise<Task[]> {
    return this.taskRepository.find();
  }

  create(task: Task): Promise<Task> {
    return this.taskRepository.save(task);
  }
}

 

6-5. task.module.ts 파일을 수정해준다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TaskController } from './task.controller';
import { TaskService } from './task.service';
import { Task } from './task.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Task])],
  controllers: [TaskController],
  providers: [TaskService],
})
export class TaskModule {}

 

6-6 main.ts 파일을 수정해준다.

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { INestApplication } from '@nestjs/common';

export function setupSwagger(app: INestApplication) {
  const options = new DocumentBuilder()
    .setTitle('NestJS Swagger')
    .setDescription('API documentation')
    .setVersion('1.0')
    .addTag('NestJS API LIST')
    .build();
  
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api-docs', app, document);
}

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  setupSwagger(app);
  await app.listen(3000);
}
bootstrap();

 

구조는 아래와 같을 것이다.

서버를 켜고 DB접속이 정상적이라면

아래와 같은 결과를 확인할수 있다.

 

http://localhost:3000/api-docs#/ 로 접속시

swagger도 정상적으로 접근되는것을 확인할수 있다.

 

 

테스트는 Talend API Tester 크롬 확장프로그램을 사용하겠다.

 

GET 데이터 조회

 

POST 데이터 조회

 

데이터의 영속성이 보장되니 db tool (dbeaver) 을 이용하여 데이터를 확인할 수 있다.

 

다음편은 Google Auth Login을 활용해 보겠다.

 

 

 

'전체 > NestJS' 카테고리의 다른 글

NestJs 토이 프로젝트 구성해보기 - 2  (0) 2023.07.16

+ Recent posts