icon

API 게이트웨이 패턴 구현


 API 게이트웨이는 마이크로서비스 아키텍처에서 중요한 역할을 하는 컴포넌트입니다.

 클라이언트와 백엔드 서비스 사이의 단일 진입점 역할을 하며, 라우팅, 프로토콜 변환, 요청 집계, 인증 등 다양한 기능을 제공합니다.

 NestJS를 사용하여 효과적인 API 게이트웨이를 구현할 수 있습니다.

API 게이트웨이의 개념과 역할

 API 게이트웨이는 다음과 같은 주요 역할을 수행합니다.

  • 라우팅 및 프록시
  • 인증 및 권한 부여
  • 요청/응답 변환
  • 로드 밸런싱
  • 서킷 브레이커
  • 로깅 및 모니터링

NestJS로 API 게이트웨이 구현하기

  1. 의존성 설치
npm install @nestjs/microservices @nestjs/axios
  1. 게이트웨이 모듈 설정
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { ApiGatewayController } from './api-gateway.controller';
 
@Module({
  imports: [
    ClientsModule.register([
      { name: 'USER_SERVICE', transport: Transport.TCP },
      { name: 'PRODUCT_SERVICE', transport: Transport.TCP },
    ]),
  ],
  controllers: [ApiGatewayController],
})
export class ApiGatewayModule {}
  1. 라우팅 및 프록시 구현
import { Controller, All, Param, Req, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { Request } from 'express';
 
@Controller('api')
export class ApiGatewayController {
  constructor(
    @Inject('USER_SERVICE') private userService: ClientProxy,
    @Inject('PRODUCT_SERVICE') private productService: ClientProxy,
  ) {}
 
  @All('users/:path')
  handleUserRequests(@Param('path') path: string, @Req() req: Request) {
    const pattern = { cmd: path };
    return this.userService.send(pattern, req.body);
  }
 
  @All('products/:path')
  handleProductRequests(@Param('path') path: string, @Req() req: Request) {
    const pattern = { cmd: path };
    return this.productService.send(pattern, req.body);
  }
}

인증 및 권한 부여

 API 게이트웨이 수준에서 인증을 구현하면 백엔드 서비스의 보안을 일관되게 관리할 수 있습니다.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { JwtService } from '@nestjs/jwt';
 
@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(private jwtService: JwtService) {}
 
  use(req: Request, res: Response, next: NextFunction) {
    const token = req.headers['authorization']?.split(' ')[1];
    if (token) {
      try {
        const decoded = this.jwtService.verify(token);
        req['user'] = decoded;
      } catch (error) {
        // 토큰 검증 실패
      }
    }
    next();
  }
}

요청 집계 및 응답 변환

 여러 마이크로서비스의 데이터를 조합하여 클라이언트에 응답할 수 있습니다.

@Get('user-with-orders/:userId')
async getUserWithOrders(@Param('userId') userId: string) {
  const [user, orders] = await Promise.all([
    this.userService.send({ cmd: 'get-user' }, { userId }).toPromise(),
    this.orderService.send({ cmd: 'get-user-orders' }, { userId }).toPromise(),
  ]);
  return { ...user, orders };
}

로드 밸런싱 및 서킷 브레이커

 NestJS의 @nestjs/microservices 모듈은 기본적인 로드 밸런싱을 제공합니다.

 서킷 브레이커는 @nestjs/circuit-breaker 패키지를 사용하여 구현할 수 있습니다.

import { CircuitBreaker } from '@nestjs/circuit-breaker';
 
@CircuitBreaker({ threshold: 5, duration: 10000 })
@Get('products')
getProducts() {
  return this.productService.send({ cmd: 'get-products' }, {});
}

API 버전 관리

 URL 기반 버전 관리 예시

@Controller('api/v1')
export class ApiV1Controller {
  // V1 API 엔드포인트
}
 
@Controller('api/v2')
export class ApiV2Controller {
  // V2 API 엔드포인트
}

모니터링, 로깅, 분산 추적

 Prometheus와 OpenTelemetry를 사용한 모니터링 및 추적 구현

import { PrometheusController } from '@willsoto/nestjs-prometheus';
import { OpenTelemetryModule } from '@metinseylan/nestjs-opentelemetry';
 
@Module({
  imports: [
    PrometheusModule.register(),
    OpenTelemetryModule.forRoot(),
  ],
  controllers: [PrometheusController],
})
export class ApiGatewayModule {}

성능 최적화 및 캐싱

 Redis를 사용한 캐싱 구현

import { CacheModule, CacheInterceptor } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-store';
 
@Module({
  imports: [
    CacheModule.register({
      store: redisStore,
      host: 'localhost',
      port: 6379,
    }),
  ],
})
export class ApiGatewayModule {}
 
@UseInterceptors(CacheInterceptor)
@Get('products')
getProducts() {
  // 이 응답은 캐시됩니다
}

Best Practices 및 주의사항

  1. 보안 강화 : HTTPS 사용, 적절한 CORS 설정
  2. 에러 처리 : 일관된 에러 응답 포맷 사용
  3. 속도 제한 : 과도한 요청으로부터 서비스 보호
  4. 문서화 : Swagger 등을 사용한 API 문서 자동화
  5. 테스트 : 단위 테스트 및 통합 테스트 구현
  6. 로깅 : 구조화된 로깅으로 문제 해결 용이성 확보
  7. 확장성 : 컨테이너화 및 오케스트레이션 도구 활용
  8. 모니터링 : 핵심 메트릭 정의 및 지속적 관찰

 NestJS를 사용한 API 게이트웨이 구현은 마이크로서비스 아키텍처의 복잡성을 효과적으로 관리할 수 있게 해줍니다.

 라우팅, 인증, 요청 집계 등의 기능을 중앙화하여 백엔드 서비스의 복잡성을 줄이고, 클라이언트와의 상호작용을 단순화할 수 있습니다.