2026幎ç NestJS ãã€ã¯ããµãŒãã¹ïŒã¢ãŒããã¯ãã£ãgRPCã颿¥å¯Ÿçã¬ã€ã
NestJS ãã€ã¯ããµãŒãã¹ã®ã¢ãŒããã¯ãã£èšèšãgRPC ãã©ã³ã¹ããŒãã®æ§æãã¹ããªãŒãã³ã°ãã¿ãŒã³ãä¿¡é Œæ§ãã¿ãŒã³ãæè¡é¢æ¥ã®é »åºè³ªåãäœç³»çã«è§£èª¬ããŸãã

2026幎çŸåšããšã³ã¿ãŒãã©ã€ãºã·ã¹ãã ã®éçºçŸå Žã§ã¯ãã¢ããªã·ãã¯ã¢ãŒããã¯ãã£ãããã€ã¯ããµãŒãã¹ãžã®ç§»è¡ãå éããŠããŸãããšããã Node.js ãšã³ã·ã¹ãã ã«ãããŠãNestJS ã¯ãã®ã¢ãžã¥ãŒã«èšèšãšå å®ããæœè±¡åã¬ã€ã€ãŒã«ããããã€ã¯ããµãŒãã¹åºç€ãšããŠé«ãè©äŸ¡ãåŸãŠããŸããNestJS ãæäŸãããã©ã³ã¹ããŒãæœè±¡åã«ãããTCPãRedisãNATSãKafkaãgRPC ãšãã£ã倿§ãªéä¿¡ãããã³ã«ãçµ±äžç㪠API ã§æ±ãããšãå¯èœã§ããæ¬èšäºã§ã¯ãNestJS ãæŽ»çšãããã€ã¯ããµãŒãã¹ã®ã¢ãŒããã¯ãã£èšèšãã gRPC ã®å®è£ ãã¹ããªãŒãã³ã°ãã¿ãŒã³ãä¿¡é Œæ§ã®ç¢ºä¿ããããŠæè¡é¢æ¥ã§åãããé »åºè³ªåãŸã§ãäœç³»çã«è§£èª¬ããŸãã
ãµãŒãã¹ééä¿¡ã«ã¯ gRPCãå€éšã¯ã©ã€ã¢ã³ãåãã«ã¯ REST ãæ¡çšããã®ãçŸä»£çãªãã€ã¯ããµãŒãã¹ã®å®ç³ã§ããgRPC 㯠Protocol Buffers ã«ãããã€ããªã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ãš HTTP/2 ã®ãã«ããã¬ãã·ã³ã°ã«ãããJSON ããŒã¹ã® REST ãšæ¯èŒããŠã¬ã€ãã³ã·ãšãã€ããŒããµã€ãºãå€§å¹ ã«åæžã§ããŸããäžæ¹ãREST ã¯ãã©ãŠã¶ãšã®äºææ§ããããã°ã®å®¹æããšããå©ç¹ãæã¡ãŸããäž¡è ã驿驿ã§çµã¿åãããããšãå®è·µçãªã¢ãããŒãã§ãã
NestJS ãã€ã¯ããµãŒãã¹ã®ãã©ã³ã¹ããŒãã¬ã€ã€ãŒã¢ãŒããã¯ãã£
NestJS ã®ãã€ã¯ããµãŒãã¹ã¢ãžã¥ãŒã«ã¯ããµãŒãã¹ééä¿¡ã®å®è£ 詳现ããã©ã³ã¹ããŒãã¬ã€ã€ãŒãšããŠæœè±¡åããŠããŸãããã®èšèšã«ãããã¢ããªã±ãŒã·ã§ã³ã®ããžãã¹ããžãã¯ããã©ã³ã¹ããŒãã®çš®é¡ããå®å šã«åé¢ã§ããŸãããã©ã³ã¹ããŒãã TCP ãã Redis ã«å€æŽããå Žåã§ããã³ã³ãããŒã©ãŒããµãŒãã¹å±€ã®ã³ãŒããæžãæããå¿ èŠã¯ãããŸããã
ãã®ã¢ãŒããã¯ãã£ã®äžæ žãæ
ãã®ãã@MessagePattern() ãš @EventPattern() ãšãã2ã€ã®ãã³ã¬ãŒã¿ã§ãã@MessagePattern() ã¯ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹åã®éä¿¡ãå®çŸããŸããåŒã³åºãå
ã®ãµãŒãã¹ã¯ã¬ã¹ãã³ã¹ãåãåããŸã§åŸ
æ©ãããããæ³šæã®äœæããŠãŒã¶ãŒæ
å ±ã®ååŸãšãã£ããçµæãå³åº§ã«å¿
èŠãšããåŠçã«é©ããŠããŸããäžæ¹ã@EventPattern() ã¯ã€ãã³ãé§ååã®éåæéä¿¡ã«äœ¿çšãããŸããã¬ã¹ãã³ã¹ãè¿ããªããã¡ã€ã¢ã»ã¢ã³ãã»ãã©ãŒã²ããæ¹åŒã§ãããéç¥ã®éä¿¡ããã°ã®èšé²ãªã©ãåŠçã®å®äºãåŸ
ã€å¿
èŠããªãã±ãŒã¹ã«åããŠããŸãã
import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern, Payload } from '@nestjs/microservices';
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create-order.dto';
@Controller()
export class OrdersController {
constructor(private readonly ordersService: OrdersService) {}
// Request-response: caller waits for the created order
@MessagePattern('order.create')
async createOrder(@Payload() data: CreateOrderDto) {
return this.ordersService.create(data);
}
// Event-based: fire and forget, no response returned
@EventPattern('order.shipped')
async handleOrderShipped(@Payload() data: { orderId: string }) {
await this.ordersService.markAsShipped(data.orderId);
}
}äžèšã®ã³ã³ãããŒã©ãŒã§ã¯ãorder.create ã¡ãã»ãŒãžãã¿ãŒã³ã«å¯ŸããŠæ³šæãäœæãããã®çµæãåŒã³åºãå
ãžè¿åŽããŠããŸããäžæ¹ãorder.shipped ã€ãã³ããåä¿¡ããå Žåã¯ã泚æãåºè·æžã¿ã«æŽæ°ããã ãã§ã¬ã¹ãã³ã¹ã¯è¿ããŸããããã®2ã€ã®ãã³ã¬ãŒã¿ã䜿ãåããããšã§ããµãŒãã¹éã®çµå床ãæå°éã«æãã€ã€ããŠãŒã¹ã±ãŒã¹ã«å¿ããæé©ãªéä¿¡æ¹åŒãéžæã§ããŸãã
ãªãã@Payload() ãã³ã¬ãŒã¿ã¯ã¡ãã»ãŒãžæ¬æããããŒã¿ãæœåºãã圹å²ãæ
ããŸããããªããŒã·ã§ã³ãã€ããšçµã¿åãããããšã§ãåä¿¡ããŒã¿ã®åå®å
šæ§ã確ä¿ããããšãå¯èœã§ãã
NestJS ãã€ã¯ããµãŒãã¹ã«ããã gRPC ãã©ã³ã¹ããŒãã®èšå®
gRPC 㯠Google ãéçºãã髿§èœ RPC ãã¬ãŒã ã¯ãŒã¯ã§ãããProtocol BuffersïŒprotobufïŒãã€ã³ã¿ãŒãã§ãŒã¹å®çŸ©èšèªãšããŠäœ¿çšããŸããHTTP/2 ãåºç€ãšãããããæ¥ç¶ã®ãã«ããã¬ãã·ã³ã°ãããããŒå§çž®ãåæ¹åã¹ããªãŒãã³ã°ãšãã£ãæ©èœãæšæºã§å©çšã§ããŸãã
NestJS ã§ gRPC ãã©ã³ã¹ããŒããå°å
¥ããã«ã¯ãæåã«ãµãŒãã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã .proto ãã¡ã€ã«ã§å®çŸ©ããŸãããã®å®çŸ©ããµãŒãã¹éã®ã³ã³ãã©ã¯ãïŒå¥çŽïŒãšãªããã¯ã©ã€ã¢ã³ããšãµãŒããŒã®åæ¹ããã®ã¹ããŒãã«åºã¥ããŠéä¿¡ãè¡ããŸãã
syntax = "proto3";
package users;
service UsersService {
rpc FindOne (UserById) returns (User);
rpc FindMany (UserFilter) returns (stream User);
}
message UserById {
string id = 1;
}
message UserFilter {
string role = 1;
int32 limit = 2;
}
message User {
string id = 1;
string email = 2;
string name = 3;
string role = 4;
}ãã® proto ãã¡ã€ã«ã§ã¯ãUsersService ã«2ã€ã® RPC ã¡ãœãããå®çŸ©ããŠããŸããFindOne ã¯åäžã®ãŠãŒã¶ãŒãè¿ããŠããªãŒ RPC ã§ãããFindMany ã¯æ¡ä»¶ã«åèŽãããŠãŒã¶ãŒãã¹ããªãŒã ã§è¿ããµãŒããŒã¹ããªãŒãã³ã° RPC ã§ããProtocol Buffers ã¯ã¹ããŒããã¡ãŒã¹ãã®ã¢ãããŒãã匷å¶ããããããµãŒãã¹éã®ã€ã³ã¿ãŒãã§ãŒã¹ãæç¢ºã«ææžåããããšãã坿¬¡çãªå©ç¹ããããŸãã
Protocol Buffers ã¯ãã€ããªåœ¢åŒã§ããŒã¿ãã·ãªã¢ã©ã€ãºãããããJSON ãšæ¯èŒããŠãã€ããŒããµã€ãºãå¹³åã§ 30-80% åæžãããŸãããŸããã·ãªã¢ã©ã€ãºã»ãã·ãªã¢ã©ã€ãºã®åŠçéåºŠãæ°åé«éã§ãããã€ã¯ããµãŒãã¹éã§å€§éã®ããŒã¿ã亀æããã·ã¹ãã ã§ã¯ããã®å·®ãå šäœã®ã¬ã€ãã³ã·ã«å€§ãã圱é¿ããŸãã
次ã«ãNestJS ã¢ããªã±ãŒã·ã§ã³ã gRPC ãã€ã¯ããµãŒãã¹ãšããŠèµ·åããããã®ããŒãã¹ãã©ããã³ãŒããèšè¿°ããŸãã
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.GRPC,
options: {
package: 'users',
protoPath: join(__dirname, 'proto/users.proto'),
url: '0.0.0.0:5000',
},
},
);
await app.listen();
}
bootstrap();Transport.GRPC ãæå®ããpackage ã«ã¯ proto ãã¡ã€ã«ã®ããã±ãŒãžåãprotoPath ã«ã¯ proto ãã¡ã€ã«ã®ãã¹ãããããèšå®ããŸããurl ã¯ãµãŒãã¹ããªãã¹ã³ããã¢ãã¬ã¹ãšããŒãã§ãã
ã³ã³ãããŒã©ãŒã§ã¯ã@GrpcMethod() ãã³ã¬ãŒã¿ã䜿çšã㊠proto ãã¡ã€ã«ã§å®çŸ©ãã RPC ã¡ãœãããšãã³ãã©ãŒã察å¿ä»ããŸãã
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { UsersService } from './users.service';
@Controller()
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@GrpcMethod('UsersService', 'FindOne')
async findOne(data: { id: string }) {
return this.usersService.findById(data.id);
}
}@GrpcMethod() ã®ç¬¬1åŒæ°ã¯ãµãŒãã¹åã第2åŒæ°ã¯ RPC ã¡ãœããåã§ããproto ãã¡ã€ã«ã®å®çŸ©ãšæ£ç¢ºã«äžèŽãããå¿
èŠããããŸããæ»ãå€ã®ãªããžã§ã¯ã㯠NestJS ãèªåçã« Protocol Buffers 圢åŒã«ã·ãªã¢ã©ã€ãºããŠã¯ã©ã€ã¢ã³ãã«è¿åŽããŸãã
NestJS ã§ã® gRPC ã¹ããªãŒãã³ã°ãã¿ãŒã³
gRPC ã REST ã«å¯ŸããŠæã€æ±ºå®çãªåªäœæ§ã®äžã€ããã¹ããªãŒãã³ã°éä¿¡ã®ãã€ãã£ããµããŒãã§ããgRPC ã«ã¯4ã€ã®éä¿¡ãã¿ãŒã³ããããŸãããŠããªãŒïŒåäžãªã¯ãšã¹ãã»åäžã¬ã¹ãã³ã¹ïŒããµãŒããŒã¹ããªãŒãã³ã°ïŒåäžãªã¯ãšã¹ãã»è€æ°ã¬ã¹ãã³ã¹ïŒãã¯ã©ã€ã¢ã³ãã¹ããªãŒãã³ã°ïŒè€æ°ãªã¯ãšã¹ãã»åäžã¬ã¹ãã³ã¹ïŒãåæ¹åã¹ããªãŒãã³ã°ïŒè€æ°ãªã¯ãšã¹ãã»è€æ°ã¬ã¹ãã³ã¹ïŒã§ãã
NestJS ã§ã¯ãRxJS ã® Observable ãæ»ãå€ãšããŠè¿ãããšã§ããµãŒããŒã¹ããªãŒãã³ã°ã宣èšçã«å®è£
ã§ããŸãã
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { GrpcMethod } from '@nestjs/microservices';
@GrpcMethod('UsersService', 'FindMany')
findMany(data: { role: string; limit: number }): Observable<any> {
// Stream users matching the filter one by one
const users$ = from(this.usersService.findByRole(data.role, data.limit));
return users$.pipe(
map((user) => ({
id: user.id,
email: user.email,
name: user.name,
role: user.role,
})),
);
}ãã®ãã¿ãŒã³ã§ã¯ããã£ã«ã¿æ¡ä»¶ã«åèŽãããŠãŒã¶ãŒãäžåºŠã«ãŸãšããŠè¿ãã®ã§ã¯ãªãã1ä»¶ãã€ã¹ããªãŒã ãšããŠéä¿¡ããŸããã¯ã©ã€ã¢ã³ãã¯ããŒã¿ãå°çãããã³ã«é次åŠçãéå§ã§ãããããæåã®ã¬ã¹ãã³ã¹ãŸã§ã®åŸ ã¡æéïŒTime to First ByteïŒãççž®ãããŸããæ°åä»¶åäœã®ããŒã¿ãè¿åŽããã±ãŒã¹ã§ã¯ãã¡ã¢ãªæ¶è²»éã®èгç¹ã§ãæå©ã§ãã
åæ¹åã¹ããªãŒãã³ã°ã§ã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒãåæã«ããŒã¿ãéåä¿¡ã§ããŸãããªã¢ã«ã¿ã€ã ãã£ãããæ ªäŸ¡ã®ã©ã€ããã£ãŒããªã©ãåæ¹åã®ç¶ç¶çãªããŒã¿ãããŒãå¿
èŠãªãŠãŒã¹ã±ãŒã¹ã«é©ããŠããŸããNestJS ã§ã¯ Subject ãæŽ»çšããŠåæ¹åã¹ããªãŒãã³ã°ãå®è£
ããããšãå¯èœã§ãã
ãã€ããªããã¢ããªã±ãŒã·ã§ã³ïŒåäžãµãŒãã¹ã§ã® HTTP ãš gRPC
ãããã¯ã·ã§ã³ç°å¢ã§ã¯ã1ã€ã®ãµãŒãã¹ã HTTP ãšã³ããã€ã³ããš gRPC ãšã³ããã€ã³ãã®äž¡æ¹ãæäŸããå¿ èŠãããå Žé¢ã¯çãããããŸãããå€éšã®ããã³ããšã³ãã¢ããªã±ãŒã·ã§ã³ã«ã¯ REST API ãå ¬éããå éšã®ãã€ã¯ããµãŒãã¹ééä¿¡ã«ã¯ gRPC ã䜿çšãããšããã¢ãŒããã¯ãã£ã¯ãããã©ãŒãã³ã¹ãšäºææ§ãäž¡ç«ãããçŸå®çãªéžæè¢ã§ãã
NestJS ã¯ãã®ãã€ããªããã¢ããªã±ãŒã·ã§ã³ãã¿ãŒã³ããã¬ãŒã ã¯ãŒã¯ã¬ãã«ã§ãµããŒãããŠããŸããNestFactory.create() ã§ HTTP ãµãŒããŒãäœæããåŸãconnectMicroservice() ã§ gRPC ãã©ã³ã¹ããŒããè¿œå æ¥ç¶ããŸãã
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';
async function bootstrap() {
// HTTP server on port 3000
const app = await NestFactory.create(AppModule);
// gRPC microservice on port 5000
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.GRPC,
options: {
package: 'users',
protoPath: join(__dirname, 'proto/users.proto'),
url: '0.0.0.0:5000',
},
});
await app.startAllMicroservices();
await app.listen(3000);
}
bootstrap();ãã®æ§æã§ã¯ãããŒã 3000 ã§ HTTP ãªã¯ãšã¹ããåŠçããããŒã 5000 ã§ gRPC åŒã³åºããåãä»ããŸããstartAllMicroservices() ããã¹ãŠã®ãã€ã¯ããµãŒãã¹ãã©ã³ã¹ããŒããèµ·åãããã®åŸ listen(3000) ã HTTP ãµãŒããŒãéå§ããŸããåäžã®ãµãŒãã¹å±€ããªããžããªãHTTP ã³ã³ãããŒã©ãŒãš gRPC ã³ã³ãããŒã©ãŒã®åæ¹ããå©çšã§ãããããã³ãŒãã®éè€ãåé¿ããªããè€æ°ãããã³ã«ã«å¯Ÿå¿ã§ããŸãã
ãã€ããªããã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã«ã¹ãã§ãã¯ãšã³ããã€ã³ãã HTTP åŽãš gRPC åŽã®äž¡æ¹ã«çšæããããšãæšå¥šãããŸããKubernetes ã® readiness/liveness probe 㯠HTTP ã§è¡ããgRPC ã®ãã«ã¹ãã§ãã¯ã«ã¯ grpc-health-check ãããã³ã«ã䜿çšãããšãéçšç£èŠã容æã«ãªããŸãã
Node.js / NestJSã®é¢æ¥å¯Ÿçã¯ã§ããŠããŸããïŒ
ã€ã³ã¿ã©ã¯ãã£ããªã·ãã¥ã¬ãŒã¿ãŒãflashcardsãæè¡ãã¹ãã§ç·Žç¿ããŸãããã
ãµãŒãã¹å¢çãšãã¡ã€ã³é§åèšèš
ãã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ã«ãããŠãæè¡çãªå®è£ ãšåçã«éèŠãªã®ããµãŒãã¹å¢çã®èšèšã§ããäžé©åãªå¢çèšå®ã¯ã忣ã¢ããªã¹ãšåŒã°ããã¢ã³ããã¿ãŒã³ãçã¿åºããã¢ããªã¹ã®åçŽããšãã€ã¯ããµãŒãã¹ã®å©ç¹ã®äž¡æ¹ã倱ãçµæãæããŸãã
ãã¡ã€ã³é§åèšèšïŒDDDïŒã®ãå¢çã¥ããããã³ã³ããã¹ããïŒBounded ContextïŒã¯ããµãŒãã¹åå²ã®æéãšããŠåºãæ¡çšãããŠããŸããåãã€ã¯ããµãŒãã¹ã¯åäžã®ããžãã¹ãã¡ã€ã³ã«å¯ŸããŠè²¬ä»»ãæã¡ãèªèº«ã®ããŒã¿ã¹ãã¢ãç¬ç«ããŠç®¡çããŸããããã¯ãDatabase per Serviceããã¿ãŒã³ãšããŠç¥ããããµãŒãã¹éã®ããŒã¿çµåãæé€ããããã®åºæ¬ååã§ãã
å ·äœçã«ã¯ãEC ãµã€ãã§ããã°ã泚æããåšåº«ãããŠãŒã¶ãŒããæ±ºæžããéç¥ããšãã£ãåäœã§ãµãŒãã¹ãåå²ããŸããåãµãŒãã¹ã¯èªèº«ã®ããŒã¿ããŒã¹ãææããä»ã®ãµãŒãã¹ã®ããŒã¿ããŒã¹ã«çŽæ¥ã¢ã¯ã»ã¹ããããšã¯ãããŸããããµãŒãã¹éã®ããŒã¿åç §ãå¿ èŠãªå Žåã¯ãgRPC ãã¡ãã»ãŒãžãã¥ãŒãéããéåæéä¿¡ã§è¡ããŸãã
NestJS ã®ã¢ãžã¥ãŒã«ã·ã¹ãã ã¯ããã®å¢çã¥ããããã³ã³ããã¹ãã®å®è£ ãšèŠªåæ§ãé«ãèšèšãšãªã£ãŠããŸããåãã¡ã€ã³ãç¬ç«ãã NestJS ã¢ãžã¥ãŒã«ãšããŠéçºããã¢ãžã¥ãŒã«éã®äŸåé¢ä¿ãæå°åããäžã§ãã¹ã±ãŒãªã³ã°ãå¿ èŠã«ãªã£ã段éã§åå¥ã®ãã€ã¯ããµãŒãã¹ãšããŠåãåºãããšãå¯èœã§ãããã®æ®µéçãªã¢ãããŒãã¯ãã¢ããªã¹ãã¡ãŒã¹ããæŠç¥ãšåŒã°ãããã¡ã€ã³ã®çè§£ãäžååãªåææ®µéã§ã®é床ãªåå²ãåé¿ã§ããŸãã
ä¿¡é Œæ§ãã¿ãŒã³ïŒã¿ã€ã ã¢ãŠãããªãã©ã€ããµãŒããããã¬ãŒã«ãŒ
忣ã·ã¹ãã ã§ã¯ãããã¯ãŒã¯éå®³ãæ¥åžžçã«çºçããŸããåäžããã»ã¹ã®ã¢ããªã¹ã§ã¯é¢æ°åŒã³åºãã倱æããããšã¯ã»ãšãã©ãããŸãããããã€ã¯ããµãŒãã¹éã®ãªã¢ãŒãåŒã³åºãã¯ããããã¯ãŒã¯é å»¶ãäžæçãªé害ãäžæµãµãŒãã¹ã®ããŠã³ãªã©ã倿§ãªçç±ã§å€±æãåŸãŸããå ç¢ãªãã€ã¯ããµãŒãã¹ãæ§ç¯ããããã«ã¯ãã¿ã€ã ã¢ãŠãããªãã©ã€ããµãŒããããã¬ãŒã«ãŒãšãã£ãä¿¡é Œæ§ãã¿ãŒã³ãå®è£ ããå¿ èŠããããŸãã
NestJS ã§ã¯ãRxJS ã®ãªãã¬ãŒã¿ã掻çšããŠãããã®ãã¿ãŒã³ã宣èšçã«çµã¿èŸŒãããšãã§ããŸãã
import { Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { firstValueFrom, timeout, retry } from 'rxjs';
@Injectable()
export class OrdersService {
private usersService: any;
constructor(@Inject('USERS_PACKAGE') private client: ClientGrpc) {}
onModuleInit() {
this.usersService = this.client.getService('UsersService');
}
async getOrderWithUser(orderId: string, userId: string) {
// 3-second deadline, 2 retries with exponential backoff
const user = await firstValueFrom(
this.usersService.findOne({ id: userId }).pipe(
timeout(3000),
retry({ count: 2, delay: (err, retryCount) => {
const jitter = Math.random() * 100;
return new Promise(r => setTimeout(r, 1000 * retryCount + jitter));
}}),
),
);
return { orderId, user };
}
}äžèšã®å®è£
ã§ã¯ã3ã€ã®ä¿¡é Œæ§ã¡ã«ããºã ãçµã¿åããããŠããŸããtimeout(3000) ã«ããã3ç§ä»¥å
ã«ã¬ã¹ãã³ã¹ãè¿ããªãå Žå㯠TimeoutError ãã¹ããŒãããŸããretry ãªãã¬ãŒã¿ã¯æå€§2åã®ãªãã©ã€ãè¡ãããªãã©ã€ééã¯ææ°ããã¯ãªãïŒ1ç§ã2ç§ãšå¢å ïŒã§å¶åŸ¡ãããŸããããã«ããžãã¿ãŒïŒã©ã³ãã ãªé
å»¶ã®äžä¹ãïŒãå ããããšã§ãè€æ°ã®ã¯ã©ã€ã¢ã³ããåæã«ãªãã©ã€ãè¡ãããªãã©ã€ã¹ããŒã ãã鲿¢ããŠããŸãã
ãµãŒããããã¬ãŒã«ãŒãã¿ãŒã³ã«ã€ããŠã¯ãNestJS ã«ã¯æšæºã®å®è£
ãå«ãŸããŠããŸããããopossum ã cockatiel ãšãã£ãã©ã€ãã©ãªãå°å
¥ããããšã§å®è£
ã§ããŸãããµãŒããããã¬ãŒã«ãŒã¯ãé£ç¶ããé害ãéŸå€ãè¶
ããå Žåã«åè·¯ãããªãŒãã³ãç¶æ
ã«åãæ¿ããäžå®æéãã¹ãŠã®ãªã¯ãšã¹ããå³åº§ã«æåŠããŸããããã«ãããé害ãçºçããŠããäžæµãµãŒãã¹ãžã®ç¡é§ãªãªã¯ãšã¹ããææ¢ããã«ã¹ã±ãŒãé害ïŒé害ã®é£éçæ³¢åïŒã鲿¢ããŸãã
NestJS ãã€ã¯ããµãŒãã¹ã®é¢æ¥è³ªå
NestJS ãçšãããã€ã¯ããµãŒãã¹éçºã«é¢ããæè¡é¢æ¥ã§ã¯ããã¬ãŒã ã¯ãŒã¯ã®æ©èœçè§£ã ãã§ãªãã忣ã·ã¹ãã ã®èšèšååã«å¯Ÿããæ·±ãçè§£ãæ±ããããŸãã以äžã«ãé »åºãã質åãšæš¡ç¯çãªåçã®èŠç¹ãæŽçããŸãã
Q1: @MessagePattern() ãš @EventPattern() ã®éãã¯äœã§ããïŒããããã®é©çšå Žé¢ã説æããŠãã ããã
@MessagePattern() ã¯ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹åã®åæéä¿¡ã«äœ¿çšããŸããåŒã³åºãå
ã¯ã¬ã¹ãã³ã¹ãåãåããŸã§åŠçãåŸ
æ©ããŸããæ³šæã®äœæããŠãŒã¶ãŒèªèšŒãªã©ãåŠççµæãåŒã³åºãå
ãå¿
èŠãšããã±ãŒã¹ã«é©ããŠããŸãã@EventPattern() ã¯ã€ãã³ãé§ååã®éåæéä¿¡ã«äœ¿çšããŸããã¬ã¹ãã³ã¹ãè¿ããªããã¡ã€ã¢ã»ã¢ã³ãã»ãã©ãŒã²ããæ¹åŒã§ãããéç¥ã¡ãŒã«éä¿¡ãç£æ»ãã°ã®èšé²ãªã©ãçµæãåŸ
ã€å¿
èŠããªãåŠçã«åããŠããŸããèšèšäžã®å€æåºæºã¯ãåŒã³åºãå
ãã¬ã¹ãã³ã¹ãå¿
èŠãšãããã©ãããã§ãã
Q2: NestJS ã§ãµããŒãããããã©ã³ã¹ããŒããããã³ã«ãšãããããã®éžå®åºæºãæããŠãã ããã
NestJS 㯠TCPãRedisãNATSãRabbitMQïŒAMQPïŒãKafkaãgRPC ã®ãã©ã³ã¹ããŒãããµããŒãããŠããŸããTCP ã¯æãã·ã³ãã«ã§å€éšäŸåããªããå°èŠæš¡ãªã·ã¹ãã ã«é©ããŠããŸããRedis ã¯Pub/Sub ã«ãã軜éãªã¡ãã»ãŒãžã³ã°ã«ãNATS ã¯é«ã¹ã«ãŒããããã€äœã¬ã€ãã³ã·ã®éä¿¡ã«åªããŠããŸããRabbitMQ ã¯ã¡ãã»ãŒãžã®æ°žç¶åãã«ãŒãã£ã³ã°ãå¿ èŠãªå Žé¢ã§éžæãããŸããKafka ã¯ã€ãã³ããœãŒã·ã³ã°ãå€§èŠæš¡ã¹ããªãŒãã³ã°ã«æé©ã§ããgRPC ã¯åå®å šæ§ãšé«ããã©ãŒãã³ã¹ãæ±ãããããµãŒãã¹ééä¿¡ã«é©ããŠããŸãã
Q3: gRPC ã REST ãããé©ããŠããã®ã¯ã©ã®ãããªå Žé¢ã§ããïŒ
gRPC 㯠Protocol Buffers ã«ãããã€ããªã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ã䜿çšãããããJSON ããŒã¹ã® REST ãšæ¯èŒããŠãã€ããŒããµã€ãºãå°ãããã·ãªã¢ã©ã€ãºé床ãé«éã§ããHTTP/2 ã®ãã«ããã¬ãã·ã³ã°ã«ãããåäžã® TCP æ¥ç¶äžã§è€æ°ã®ãªã¯ãšã¹ãã䞊è¡åŠçã§ããŸããããã«ãåæ¹åã¹ããªãŒãã³ã°ã®ãã€ãã£ããµããŒãã«ããããªã¢ã«ã¿ã€ã ããŒã¿ã®é ä¿¡ã«ã察å¿å¯èœã§ãããã ãããã©ãŠã¶ããã®çŽæ¥ã¢ã¯ã»ã¹ã«ã¯åããªãããããµãŒãã¹ééä¿¡ã«äœ¿çšããå€éšåãã«ã¯ REST ã GraphQL ã䜵çšããã®ãäžè¬çã§ãã
Q4: ãã€ã¯ããµãŒãã¹ã«ããã忣ãã©ã³ã¶ã¯ã·ã§ã³ã®åŠçæ¹æ³ã«ã€ããŠèª¬æããŠãã ããã
忣ãã©ã³ã¶ã¯ã·ã§ã³ã¯ Saga ãã¿ãŒã³ã§åŠçããã®ãæšæºçãªã¢ãããŒãã§ããã³ã¬ãªã°ã©ãã£ãŒæ¹åŒã§ã¯ãåãµãŒãã¹ãåŠçå®äºåŸã«ã€ãã³ããçºè¡ããæ¬¡ã®ãµãŒãã¹ãããã賌èªããŠåŠçãç¶ç¶ããŸãããµãŒãã¹éã®çŽæ¥çãªäŸåé¢ä¿ããªããççµåãç¶æã§ããŸãããªãŒã±ã¹ãã¬ãŒã·ã§ã³æ¹åŒã§ã¯ãäžå€®ã® Saga ãªãŒã±ã¹ãã¬ãŒã¿ããã©ã³ã¶ã¯ã·ã§ã³å šäœã®ãããŒãå¶åŸ¡ããŸããåŠçãéäžã§å€±æããå Žåã¯ãè£åãã©ã³ã¶ã¯ã·ã§ã³ïŒcompensating transactionïŒãå®è¡ããŠããããŸã§ã«å®äºããåŠçãåãæ¶ããŸãã
Q5: ãµãŒããããã¬ãŒã«ãŒãã¿ãŒã³ã®åäœåçãšããã€ã¯ããµãŒãã¹ã«ãããå¿ èŠæ§ã説æããŠãã ããã
ãµãŒããããã¬ãŒã«ãŒã¯ãäžæµãµãŒãã¹ã®é害ãã·ã¹ãã å šäœã«æ³¢åããã«ã¹ã±ãŒãé害ã鲿¢ããããã®ãã¿ãŒã³ã§ãããã¯ããŒãºããç¶æ ã§ã¯ãªã¯ãšã¹ããéåžžéã転éããŸããé害çãéŸå€ãè¶ ãããšããªãŒãã³ãç¶æ ã«é·ç§»ãããã¹ãŠã®ãªã¯ãšã¹ããå³åº§ã«æåŠããŠãã©ãŒã«ããã¯å€ãè¿ããŸããäžå®æéçµéåŸã«ãããŒããªãŒãã³ãç¶æ ãšãªããå°æ°ã®ãªã¯ãšã¹ãã詊è¡ããŠäžæµãµãŒãã¹ã®å埩ã確èªããŸããå埩ã確èªãããã°ãã¯ããŒãºããã«æ»ããäŸç¶ãšããŠé害ãç¶ããŠããã°å床ããªãŒãã³ãã«ãªããŸãã
ä»ããç·Žç¿ãå§ããŸãããïŒ
颿¥ã·ãã¥ã¬ãŒã¿ãŒãšæè¡ãã¹ãã§ç¥èããã¹ãããŸãããã
ãŸãšã
æ¬èšäºã§ã¯ãNestJS ãåºç€ãšãããã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ã®äž»èŠãªæŠå¿µãšå®è£ ãã¿ãŒã³ã解説ããŸããã
- ãã©ã³ã¹ããŒãã¬ã€ã€ãŒ:
@MessagePattern()ã«ãããªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹éä¿¡ãš@EventPattern()ã«ããã€ãã³ãé§åéä¿¡ã䜿ãåããããšã§ããµãŒãã¹éã®çµå床ãé©åã«å¶åŸ¡ã§ããŸã - gRPC ãã©ã³ã¹ããŒã: Protocol Buffers ã«ããã¹ããŒãå®çŸ©ãš NestJS ã®
@GrpcMethod()ãã³ã¬ãŒã¿ã«ãããåå®å šã§é«æ§èœãªãµãŒãã¹ééä¿¡ãæ§ç¯ã§ããŸã - ã¹ããªãŒãã³ã°: RxJS ã® Observable ãæŽ»çšãããµãŒããŒã¹ããªãŒãã³ã°ã«ããã倧éããŒã¿ã®é次é ä¿¡ãšã¡ã¢ãªå¹çã®åäžãå®çŸã§ããŸã
- ãã€ããªããã¢ããªã±ãŒã·ã§ã³: HTTP ãš gRPC ãåäžããã»ã¹ã§æäŸããããšã§ãå€éšåã REST API ãšå éšåã gRPC ã1ã€ã®ã³ãŒãããŒã¹ã§ç®¡çã§ããŸã
- ãµãŒãã¹å¢ç: DDD ã®å¢çã¥ããããã³ã³ããã¹ãã«åºã¥ããèšèšãšãDatabase per Service ãã¿ãŒã³ã®æ¡çšãã忣ã¢ããªã¹ã®åé¿ã«äžå¯æ¬ ã§ã
- ä¿¡é Œæ§ãã¿ãŒã³: ã¿ã€ã ã¢ãŠããææ°ããã¯ãªãä»ããªãã©ã€ããµãŒããããã¬ãŒã«ãŒã®3å±€æ§é ã«ããã忣ç°å¢ç¹æã®é害ã«å¯Ÿããèæ§ã確ä¿ã§ããŸã
- 颿¥å¯Ÿç: ãã¬ãŒã ã¯ãŒã¯ã® API ã ãã§ãªãããã©ã³ã¹ããŒãã®éžå®åºæºãSaga ãã¿ãŒã³ããµãŒããããã¬ãŒã«ãŒãšãã£ã忣ã·ã¹ãã èšèšã®ååã«å¯Ÿããçè§£ãéèŠã§ã
ã¿ã°
å ±æ
é¢é£èšäº

NestJS颿¥ïŒGuardsãInterceptorsãã¢ãžã¥ã©ãŒã¢ãŒããã¯ãã£
GuardsãInterceptorsãã¢ãžã¥ã©ãŒã¢ãŒããã¯ãã£ã«é¢ããNestJSæè¡é¢æ¥ã®é »åºè³ªåããå ·äœçãªTypeScriptã³ãŒãäŸãšæè¡è§£èª¬ãšãšãã«ç޹ä»ããŸãã

NestJS + PrismaïŒNode.js ã®ããã®ã¢ãã³ãªããã¯ãšã³ãã¹ã¿ãã¯
NestJS ãš Prisma ã«ããã¢ãã³ãªããã¯ãšã³ã API æ§ç¯ã®å®å šã¬ã€ãã§ããã»ããã¢ãããã¢ãã«ããµãŒãã¹ããã©ã³ã¶ã¯ã·ã§ã³ããã¹ããã©ã¯ãã£ã¹ã解説ããŸãã

NestJS: æ¬æ ŒçãªREST APIã®æ§ç¯ã¬ã€ã
NestJSã§æ¬æ ŒçãªREST APIãæ§ç¯ããããã®å®å šã¬ã€ãã§ããã³ã³ãããŒã©ãŒããµãŒãã¹ãã¢ãžã¥ãŒã«æ§æãclass-validatorã«ããããªããŒã·ã§ã³ããšã©ãŒãã³ããªã³ã°ãå®è·µçã«è§£èª¬ããŸãã