1. Order Proto 정의 (order.proto)
주문과 관련된 gRPC 서비스 인터페이스를 정의합니다.
syntax = "proto3";
package order;
service OrderService {
rpc DeliveryStarted(DeliveryStartedRequest) returns (DeliveryStartedResponse);
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
}
message DeliveryStartedRequest {
string id = 1;
}
message DeliveryStartedResponse {}
message CreateOrderRequest {
message Meta {
message UserPayload {
string sub = 1;
}
UserPayload user = 1;
}
message Address {
string name = 1;
string street = 2;
string city = 3;
string postalCode = 4;
string country = 5;
}
message Payment {
string paymentMethod = 1;
string paymentName = 2;
string cardNumber = 3;
string expiryYear = 4;
string expiryMonth = 5;
string birthOrRegistration = 6;
string passwordTwoDigits = 7;
double amount = 8;
}
Meta meta = 1;
repeated string productIds = 2;
Address address = 3;
Payment payment = 4;
}
message CreateOrderResponse {
message Customer {
string userId = 1;
string email = 2;
string name = 3;
}
message Product {
string productId = 1;
string name = 2;
double price = 3;
}
message DeliveryAddress {
string name = 1;
string street = 2;
string city = 3;
string postalCode = 4;
string country = 5;
}
message Payment {
string paymentId = 1;
string paymentMethod = 2;
string paymentName = 3;
double amount = 4;
}
Customer customer = 1;
repeated Product products = 2;
DeliveryAddress deliveryAddress = 3;
string status = 4;
Payment payment = 5;
}
✅ 설명
DeliveryStarted: 배송 시작 이벤트를 처리
CreateOrder: 주문 생성 요청을 처리
Request/Response 메시지: 사용자 정보, 상품 목록, 배송지, 결제 정보 포함
2. OrderController 구현
NestJS에서 gRPC와 이벤트 패턴을 이용하여 주문 서비스의 엔드포인트를 작성합니다.
import { Controller, UseInterceptors } from '@nestjs/common';
import { OrderService } from './order.service';
import { CreateOrderDto } from './dto/create-order.dto';
import { EventPattern, MessagePattern, Payload } from '@nestjs/microservices';
import { RpcInterceptor } from '@app/common';
import { DeliveryStartedDto } from './dto/delivery-started.dto';
import { OrderStatus } from './entity/order.entity';
@Controller('order')
export class OrderController {
constructor(private readonly orderService: OrderService) {}
@EventPattern({ cmd: 'delivery_started' })
@UseInterceptors(RpcInterceptor)
async deliveryStarted(@Payload() payload: DeliveryStartedDto) {
console.log('deliveryStartedDto', payload);
this.orderService.changeOrderStatus(
payload.id,
OrderStatus.deliveryStarted,
);
}
@MessagePattern({ cmd: 'create_order' })
async createOrder(@Payload() createOrderDto: CreateOrderDto) {
console.log('???? OrderController createOrder', createOrderDto);
return this.orderService.createOrder(createOrderDto);
}
}
✅ 설명
@EventPattern은 비동기 이벤트를 수신 (배송 시작 등)
@MessagePattern은 RPC 방식으로 주문 생성 요청을 처리
RpcInterceptor를 사용하여 응답 형식 및 에러 처리 표준화
3. Order 엔티티 정의
Mongoose를 사용하여 주문(Order) 스키마를 정의합니다.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Customer, CustomerSchema } from './customer.entity';
import { Product, ProductSchema } from './product.entity';
import { DeliveryAddress, DeliveryAddressSchema } from './delivery-address.entity';
import { Payment, PaymentSchema } from './payment.entity';
import { Document, ObjectId } from 'mongoose';
export enum OrderStatus {
pending = 'Pending',
paymentCancelled = 'PaymentCancelled',
paymentFailed = 'PaymentFailed',
paymentProcessed = 'PaymentProcessed',
deliveryStarted = 'DeliveryStarted',
deliveryDone = 'DeliveryDone',
}
@Schema()
export class Order extends Document<ObjectId> {
@Prop({ type: CustomerSchema, required: true })
customer: Customer;
@Prop({ type: [ProductSchema], required: true })
products: Product[];
@Prop({ type: DeliveryAddressSchema, required: true })
deliveryAddress: DeliveryAddress;
@Prop({ enum: OrderStatus, default: OrderStatus.pending })
status: OrderStatus;
@Prop({ type: PaymentSchema, required: true })
payment: Payment;
}
export const OrderSchema = SchemaFactory.createForClass(Order);
✅ 설명
OrderStatus enum으로 주문 상태를 관리
customer, products, deliveryAddress, payment를 하위 스키마로 포함
주문의 라이프사이클: 생성 → 결제 확인 → 배송 시작 → 배송 완료
4. DTO 정의
CreateOrderDto
import { Type } from 'class-transformer';
import { IsArray, IsNotEmpty, IsString, ValidateNested } from 'class-validator';
import { AddressDto } from './address.dto';
import { PaymentDto } from './payment.dto';
import { UserMeta, UserPayloadDto } from '@app/common';
export class CreateOrderDto implements UserMeta {
@ValidateNested()
@IsNotEmpty()
meta: { user: UserPayloadDto };
@IsString()
@IsNotEmpty()
token: string;
@IsArray()
@IsString({ each: true })
@IsNotEmpty({ each: true })
productIds: string[];
@ValidateNested()
@Type(() => AddressDto)
@IsNotEmpty()
address: AddressDto;
@ValidateNested()
@Type(() => PaymentDto)
@IsNotEmpty()
payment: PaymentDto;
}
UserPayloadDto
import { IsNotEmpty, IsString } from 'class-validator';
export class UserPayloadDto {
@IsString()
@IsNotEmpty()
sub: string;
}
5. 동작 흐름
클라이언트가 주문 생성 요청을 보냄 → create_order RPC 호출
OrderController에서 CreateOrderDto 검증 후 OrderService.createOrder 호출
주문 생성 → 결제 처리 → 알림(Notification) 서비스 호출
배송 단계에 도달하면 delivery_started 이벤트 수신 후 상태 변경













댓글 ( 0)
댓글 남기기