로그인, 파일 업로드, 결제 등 필요한 역할별로 개발을 하고, 개발이 완료되면 하나로 묶어서 배포
한 프로젝트를 여러 작은 서비스로 분리하여 개발하고 운영, 배포하는 방법 → 여러 모듈로 분리했기 때문에 팀별로 독립적으로 개발 가능 → 마이크로서비스로 분리하게 되면 어떠한 기능에 장애가 생겨도 해당 API만 사용이 불가능하고, 다른 기능에는 문제없이 서비스 운영 가능
인증/인가를 담당하는 auth API를 따로 분리하고, 나머지 부분을 resource로 분리
api-gateway, auth, resource 필요
//auth 폴더의 main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP, // 마이크로서비스는 기본적으로 TCP 레이어 사용,
//네트워크 전송 계층 지정
options: { host: 'auth-service', port: 3001 },
//두번째 값으로는 host 이름과 port를 지정
},
);
await app.listen();
}
bootstrap();
//resource 폴더의 main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: { host: 'resource-service', port: 3002 },
}, // 포트와 호스트이름 변경
);
await app.listen();
}
bootstrap();
//auth 폴더의 app.controller.ts 파일에 login API
import { Controller } from '@nestjs/common';
import { AppService } from './app.service';
import { MessagePattern } from '@nestjs/microservices';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@MessagePattern({ cmd: 'login' })
//메세지 패턴을 통해 gateway에서 각각의 API로 요청을 전달
login(data) {
console.log(data);
return 'login 성공!!';
}
}
//resource 폴더의 app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@MessagePattern({ cmd22: 'fetchBoards' })
fetchBoards(data) {
console.log(data);
return 'fetchBoards 게시글 데이터 보내주기';
}
}
//api-gateway 폴더의 app.controller.ts
import { Controller, Get, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
@Controller()
export class AppController {
constructor(
@Inject('AUTH_SERVICE') private readonly clientAuthService: ClientProxy,
@Inject('RESOURCE_SERVICE')
private readonly clientResourceService: ClientProxy,
) {}
@Get('/auth/login')
login() {
return this.clientAuthService.send({ cmd: 'login' }, { name: '철수' });
}//API에 넘겨줄 데이터 값이 있다면 두번째 인자로 지정
@Get('boards')
fetchBoards() {
return this.clientResourceService.send({ cmd: 'fetchBoards' }, { age: 13 });
}
}
// auth 폴더의 main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3001);
}
bootstrap();
Rest-API 파일 설정과는 다르게 GraphQL-API은 각각 독립적으로 움직이므로 별다른 설정 없이 각 서비스들의 포트번호 설정값만 변경
//api-gateway 폴더의 app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloGatewayDriver, ApolloGatewayDriverConfig } from '@nestjs/apollo';
import { IntrospectAndCompose } from '@apollo/gateway';
@Module({
imports: [
GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
driver: ApolloGatewayDriver,
gateway: {
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'auth', url: 'http://auth-service:3001/graphql' },
{ name: 'resource', url: 'http://resource-service:3002/graphql' },
],
}),
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Nest에서 GraphQL을 마이크로서비스로 분리하기 위해 Federation을 사용
//auth 폴더의 app.module.ts의 Federation을 사용
//resource 폴더의 app.module.ts의 Federation을 사용
import { Module } from '@nestjs/common';
// import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { AppResolver } from './app.resolver';
import {
ApolloFederationDriver,
ApolloFederationDriverConfig,
} from '@nestjs/apollo';
@Module({
imports: [
GraphQLModule.forRoot<ApolloFederationDriverConfig>({
driver: ApolloFederationDriver,
autoSchemaFile: 'src/commons/graphql/schema.gql',
}),
],
// controllers: [AppController],
providers: [AppService, AppResolver],
})
export class AppModule {}