๐ก 03. ์๋น์ค์ ํ๋ก๋ฐ์ด๋ โ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ์ ์ด์ ์ญ์ (IoC)
๐ ๊ฐ์
๋น์ฆ๋์ค ๋ก์ง์ ํต์ฌ์ธ ์๋น์ค์, ์ด๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํด ์ฃผ๋ ๋ง๋ฒ ๊ฐ์ ์์คํ ์ธ 'ํ๋ก๋ฐ์ด๋(Provider)์ ์์กด์ฑ ์ฃผ์ (DI)'์ ๋ง์คํฐํฉ๋๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ ์๋น์ค (Service) โ ์๋ฆฌ๋ฅผ ์ ๋ดํ๋ ์ ฐํ ๐ก
- ๐งฉ ์์กด์ฑ ์ฃผ์ (DI) โ ๋๋ํ ์ธ์ฌ๊ด๋ฆฌ ์์คํ ๐ข
- ๐งช ๋ฐ๋ผํด๋ณด๊ธฐ: ์ค์ CRUD ์๋น์ค ๊น์๋ณด๊ธฐ
- ๐ผ ๋ฒ ์คํธ ํ๋ํฐ์ค์ ์ค๋ฌด ํ
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐๏ธ ์นํธ์ํธ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 20๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 10๋ถ
๐งณ ์ ์ ์ง์ ์ฒดํฌ๋ฆฌ์คํธ
- 02์ฅ ์ปจํธ๋กค๋ฌ์ ์ญํ (์์ฒญ ์์ ๋ฐ ์๋ต ๋ฐํ)์ ์์ ํ ์ดํดํ๋ค.
- TypeScript์
constructor(private readonly ...)๋ฌธ๋ฒ์ด ๋ฌด์์ ์๋ฏธํ๋์ง ์๋ค. - (์ ํ) ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์ '์ธํฐํ์ด์ค(Interface)' ๊ฐ๋ ์ ๋ค์ด๋ณธ ์ ์ด ์๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
์๋น์ค์ ํ์์ฑ โ DI(์์กด์ฑ ์ฃผ์
)์ ๊ฐ๋ ฅํจ โ ์ค์ DB ์ฐ๊ฒฐ ์ฝ๋ ์์ฑ โ ์ปค์คํ
ํ๋ก๋ฐ์ด๋ โ ์ํ ์ฐธ์กฐ ์๋ฌ ํด๊ฒฐ๋ฒ
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ์ปจํธ๋กค๋ฌ์์ ๋น์ฆ๋์ค ๋ก์ง์ ์๋ฒฝํ๊ฒ ๋ถ๋ฆฌํ์ฌ ์๋น์ค๋ก ์ฎ๊ธธ ์ ์๋ค.
- "์์กด์ฑ ์ฃผ์ ์ ์ ์ฐ๋์?" ๋ผ๋ ์ง๋ฌธ์ ๋น๋นํ๊ฒ ๋๋ตํ ์ ์๋ค.
- ์ธํฐํ์ด์ค๋ฅผ ํ์ฉํด ํ ์คํธํ๊ธฐ ์ฌ์ด(Mocking ๊ฐ๋ฅํ) ์ฝ๋๋ฅผ ์งค ์ ์๋ค.
๐ค ์ ์์์ผ ํ๋๊ฐ
์ด๋ณด ๊ฐ๋ฐ์๋ค์ ํํ "๋ผ์ฐํฐ ํ๋๊ณ ๊ทธ ์์์ DB๋ ๋ถ๋ฅด๊ณ , ๊ณ์ฐ๋ ํ๊ณ , ์๋ฌ๋ ๋ฑ์ผ๋ฉด ๋๋ ๊ฑฐ ์๋์ผ?" ๋ผ๊ณ ์ฐฉ๊ฐํด.
ํ์ง๋ง ๋ก์ง์ด ๋ณต์กํด์ง์๋ก ์ปจํธ๋กค๋ฌ๋ ๋ฑ๋ฑํด์ง๊ณ , ๋์ค์ "๊ฒฐ์ ๋ก์ง"๋ง ๋ ๋ผ์ด์ "์ค์ผ์ค๋ฌ"์์ ์ฌ์ฌ์ฉํ๊ณ ์ถ์ด๋ ๋ผ์ด๋ผ ์๊ฐ ์์ด.
์๋น์ค๋ฅผ ๋ถ๋ฆฌํ๊ณ DI๋ฅผ ํ์ฉํ๋ฉด ๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ์ฝ๋๋ฅผ ์์ ์์ฌ๋ก ๋๋ค ๋ถ์๋ค(์ฌ์ฌ์ฉ) ํ ์ ์๊ณ , ๋ฌด์๋ณด๋ค ํ
์คํธ ์ฝ๋ ์์ฑ์ด 100๋ฐฐ ์ฌ์์ ธ.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์ปจํธ๋กค๋ฌ์ ๋ก์ง์ ๋ค ์ง๋ ๊ฒ (โ)
= ์จ์ดํฐ๊ฐ ์๋ ์ฃผ๋ฌธ์ ๋ฐ์๋ง์, ๋ณธ์ธ์ด ์ฃผ๋ฐฉ์ผ๋ก ๋ฌ๋ ค๊ฐ์ ํ๋ผ์ดํฌ์ ์ก๊ณ ๊ณ ๊ธฐ๋ฅผ ๊ตฝ๋ ๊ฑฐ์ผ. ๊ทธ๋ฌ๋ค ์๋ ์ค๋ฉด ๋ ๋ฐ์ด๋๊ฐ๊ณ ! ์๋น์ด ์๋ง์ง์ฐฝ์ด ๋๊ฒ ์ง?
์๋น์ค๋ฅผ ๋ง๋ค๊ณ ์์กด์ฑ์ ์ฃผ์
ํ๋ ๊ฒ (โ
)
= ์จ์ดํฐ๋ ์ฃผ๋ฌธ๋ง ๋ฐ๊ณ ์ฃผ๋ฐฉ์ ํ ์คํด. ์ฃผ๋ฐฉ์๋ '์ดํ๋ฆฌ์ ์
ฐํ', 'ํ์ ์
ฐํ(์๋น์ค๋ค)'๊ฐ ๊ฐ์์ ๋ฉ๋ดํ๋ฅผ ๋ค๊ณ ๋๊ธฐํ๊ณ ์์ด.
์จ์ดํฐ๊ฐ ์ถ๊ทผํ ๋ "์ ์ค๋ ์ดํ๋ฆฌ์ ์
ฐํ๋ ์ผํ ๊ฒ์!" ๋ผ๊ณ ํ๋ฉด, ์๋น ์ง๋ฐฐ์ธ(NestJS DI ์ปจํ
์ด๋) ์ด ์์์ ๊ทธ๋ ์ปจ๋์
์ด ์ ์ผ ์ข์ ์ดํ๋ฆฌ์ ์
ฐํ๋ฅผ ์จ์ดํฐ ํํธ๋๋ก ๋ฑ! ๋ฐฐ์ ํด ์ฃผ๋ ๊ฑฐ์ผ.
๐งฉ ์๋น์ค (Service) โ ์๋ฆฌ๋ฅผ ์ ๋ดํ๋ ์ ฐํ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
@Injectable()์ ์๋ฏธ๋ฅผ ์๊ณ , ๋น์ฆ๋์ค ๋ก์ง์ ์์น๋ฅผ ํ์ ํ ์ ์๋ค.
์๋น์ค๋ ๋น์ฆ๋์ค ๋ก์ง ์ ๋ด๋นํ๋ ํ๋ฒํ TypeScript ํด๋์ค์ผ. ๋จ ํ๋์ ์ฐจ์ด์ ์ ๋จธ๋ฆฌ ์์ @Injectable() ์ด๋ผ๋ ์๊ด์ ์ฐ๊ณ ์๋ค๋ ์ ์ด์ง.
import { Injectable } from '@nestjs/common';
// "์ด ํด๋์ค๋ NestJS ๋ฉ๋ด์ผ์ ๋ฑ๋ก๋ ์ ์ ์
ฐํ์
๋๋ค!"
@Injectable()
export class UsersService {
// ์ค์ ๋น์ฆ๋์ค ๋ก์ง
calculateTax(amount: number) {
return amount * 0.1;
}
}๐ ์ฉ์ด:
Provider(ํ๋ก๋ฐ์ด๋)
NestJS์์ DI(์์กด์ฑ ์ฃผ์ ) ์์คํ ์ด ๊ด๋ฆฌํ๋ ๋ชจ๋ ํด๋์ค๋ฅผ ํตํ์ด 'ํ๋ก๋ฐ์ด๋'๋ผ๊ณ ๋ถ๋ฌ. ์๋น์ค๋ ํ๋ก๋ฐ์ด๋์ ๊ฐ์ฅ ํํ 90%์ง๋ฆฌ ํํ์ผ ๋ฟ์ด์ผ. ๋์ค์๋ ํฉํ ๋ฆฌ๋ ํ๋ก๋ฐ์ด๋๊ณ , ์ค์ ๊ฐ ๋ฌธ์์ด๋ ํ๋ก๋ฐ์ด๋๋ก ๋ง๋ค ์ ์์ด.
๐งฉ ์์กด์ฑ ์ฃผ์ (DI) โ ๋๋ํ ์ธ์ฌ๊ด๋ฆฌ ์์คํ ๐ข
์ด ํํธ๊ฐ NestJS์ ์ฌ์ฅ์ด์ผ.
โ ์์กด์ฑ์ ์ง์ ๋ง๋ค๋ฉด ์๊ธฐ๋ ๋น๊ทน:
class UsersController {
// ์จ์ดํฐ๊ฐ ์ถ๊ทผํ ๋๋ง๋ค ์๊ธฐ ๋์ผ๋ก ์
ฐํ๋ฅผ ์ง์ ๊ณ ์ฉํจ
private usersService = new UsersService(new DatabaseService());
}์ด๋ฌ๋ฉด DatabaseService๊ฐ ๋ฐ๋๋ฉด ์ปจํธ๋กค๋ฌ์ ์ฝ๋๊น์ง ํจ๊ป ๋ฏ์ด๊ณ ์ณ์ผ ํด. ๊ฐํ ๊ฒฐํฉ(Tight Coupling)์ ์ ํ์ด์ง.
โ NestJS์ ๊ฐ๋ ฅํ DI ํด๊ฒฐ์ฑ :
@Controller('users')
export class UsersController {
// "์ง๋ฐฐ์ธ๋, ์ UsersService ํ ์ค ์๋ ์ฌ๋ ํ ๋ช
๋ฐฐ์ ํด์ฃผ์ธ์"
constructor(private readonly usersService: UsersService) {}
}์ฐ๋ฆฌ๋ ๋จ์ง constructor์ ํ๋ผ๋ฏธํฐ ํ์
ํ์(: UsersService)๋ง ์ ์ด์ฃผ๋ฉด ๋์ด์ผ.
NestJS๊ฐ ์คํ๋ ๋, ๋๋ํ ์ง๋ฐฐ์ธ(IoC Container)์ด ์ด ํ์
์ ๋ณด๊ณ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋ UsersService ์ธ์คํด์ค๋ฅผ ์์์ ์ ๋ฃ์ด์ค.
์ด๊ฑธ ์ ์ด์ ์ญ์ (IoC, Inversion of Control) ์ด๋ผ๊ณ ๋ถ๋ฌ! ๊ฐ๋ฐ์(๋)๊ฐ new๋ฅผ ์ ํ๊ณ ํ๋ ์์ํฌ๊ฐ ์์์ ํด์ค๋ค๋ ๋ป์ด์ผ.
ํ๋ก๋ฐ์ด๋์ ์๋ช ์ฃผ๊ธฐ (Scope)
๊ธฐ๋ณธ์ ์ผ๋ก ์ง๋ฐฐ์ธ์ ์
ฐํ๋ฅผ ๋ฑ 1๋ช
๋ง ๊ณ ์ฉํด์, ๋ชจ๋ ์จ์ดํฐ๊ฐ ๋๋ ค์ฐ๊ฒ ํด (** ์ฑ๊ธํค, Singleton**). ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋ผ๊ธฐ ์ํด์์ง.
ํ์ง๋ง ํน๋ณํ ์ต์
์ ์ค ์๋ ์์ด.
| ์ค์ฝํ | ์์ฑ | ์ธ์ ์ฐ๋? | ๋จ์ |
|---|---|---|---|
| ๊ธฐ๋ณธ(DEFAULT) | ์ฑ๊ธํค. ์ฑ ์์ ์ ํ ๋ฒ ์์ฑ | 99%์ ์๋น์ค, ๋ฌด์ํ ๋ก์ง | ์์ (๊ฐ์ฅ ๋น ๋ฆ) |
| ์์ฒญ(REQUEST) | ํด๋ผ์ด์ธํธ์ 1์์ฒญ๋ง๋ค ์๋ก ์์ฑ | ์ ์ ๋ณ ํ ํฐ์ด๋ ํ ๋ํธ ์๋ณ์ด ํ์ํ ๋ | ์ฑ๋ฅ ์ ํ (๋งค๋ฒ ์์ฑ/ํ๊ดด) |
| ์์(TRANSIENT) | ์ฃผ์ ๋ฐ์ ๊ณณ์ ๋ง๋ ๋๋ง๋ค ์๋ก ์์ฑ | ๊ฐ๊ฐ ์์ ํ ๊ฒฉ๋ฆฌ๋ ์ํ(State)๋ฅผ ๊ฐ์ ธ์ผ ํ ๋ | ๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ ์ฃผ์ |
์ฌ์ฉ๋ฒ: @Injectable({ scope: Scope.REQUEST })
๐งช ๋ฐ๋ผํด๋ณด๊ธฐ: ์ค์ CRUD ์๋น์ค ๊น์๋ณด๊ธฐ
๋ง๋ณด๋จ ์ฝ๋์ง. ์ค๋ฌด์์ ๊ฐ์ฅ ๋ง์ด ์ง๊ฒ ๋ , Drizzle ORM์ ๋ถ์ธ ์ ์ (์ฃผ์) ๊ฒ์ํ CRUD ๋ผ๋์ผ.
import { Injectable, NotFoundException } from '@nestjs/common';
import { eq } from 'drizzle-orm';
import { stocks, Stock, NewStock } from '@repo/schema';
@Injectable()
export class StocksService {
// 1. DB ์๋น์ค ์ฃผ์
๋ฐ๊ธฐ
constructor(private readonly db: DatabaseService) {}
// 2. ์์ฑ (Create)
async create(data: NewStock): Promise<Stock> {
const [stock] = await this.db.insert(stocks).values(data).returning();
return stock;
}
// 3. ๋จ์ผ ์กฐํ (Read)
async findBySymbol(symbol: string): Promise<Stock> {
const stock = await this.db.query.stocks.findFirst({
where: eq(stocks.symbol, symbol),
});
// ๐ฅ ์ค์: ์ปจํธ๋กค๋ฌ ๋์ ์๋น์ค์์ ์ผ์ฐ ์๋ฌ๋ฅผ ๋์ง๋ค!
if (!stock) {
throw new NotFoundException(`์ฆ๊ถ ์ฌ๋ณผ '${symbol}'์(๋ฅผ) ์ฐพ์ ์ ์์ต๋๋ค.`);
}
return stock;
}
// 4. ์ญ์ (Delete)
async remove(symbol: string): Promise<void> {
await this.findBySymbol(symbol); // ์๋ ํ์ธ๋ถํฐ ํ๊ณ (์์ผ๋ฉด ์์์ ์์ธ ๋ฐ์)
await this.db.delete(stocks).where(eq(stocks.symbol, symbol));
}
}๐ค ๋ฅ๋์ ํ์ ํธ๋ฆฌ๊ฑฐ: ์ฌ๊ธฐ์ ๋ง์ฝ
NotFoundException์ ์ฃผ์ ์ฒ๋ฆฌํ๋ฉด, ์ปจํธ๋กค๋ฌ์์ ๋น ๊ฐ์ ๋ฐ์์ ๋ ์ฌ์ฉ์์๊ฒ ์ด๋ค ์๋ต์ด ๋ด๋ ค๊ฐ๊น? (์ ๋ต: ๋น ๊ฐ์ฒด์ด๊ฑฐ๋, 200 OK์ ํจ๊ป ๋ด์ฉ์ด ์๋ ์๋ต์ด ๋ด๋ ค๊ฐ์ ๋ฒ๊ทธ๋ฅผ ์ ๋ฐํด! ์๋น์ค์์ ์ปท ์น๋ ๊ฒ ๋ง์.)
๐ผ ๋ฒ ์คํธ ํ๋ํฐ์ค์ ์ค๋ฌด ํ ๐ก
1. ๊ฑฐ๋ํ ์๋น์ค๋ฅผ ๋ ์๊ฒ ์ชผ๊ฐ๊ธฐ
UsersService ํ๋๊ฐ 2,000์ค์ด ๋์ด๊ฐ๋ฉด ์ํ ์ ํธ์ผ. ๊ด๋ จ๋ ์๋น์ค๋ค์ ๋ ์ชผ๊ฐ๊ณ , ๊ทธ ์๋น์ค๋ผ๋ฆฌ ์๋ก ์ฃผ์
๋ฐ๊ฒ ํด.
์: UserAuthService, UserProfileService, UserPointsService
2. ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก๊ทธ๋๋ฐ (์ปค์คํ ํ๋ก๋ฐ์ด๋ ๊ฟํ)
์ธ๋ถ ๋ฉ์ผ ๋ฐ์ก ์๋น์ค(์: SendGrid)๋ฅผ ์ง์ ์ฃผ์ ๋ฐ์ผ๋ฉด, ๋์ค์ AWS SES๋ก ๊ฐ์ํ ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ค ์์ ํด์ผ ํด.
// 1. ๊ท๊ฒฉ์ ์ ํจ
export interface IEmailService {
send(to: string, content: string): Promise<void>;
}
// 2. ๊ตฌํ์ฒด
@Injectable()
export class SendGridEmailService implements IEmailService { ... }
// 3. ๋ชจ๋์์ '๋ฐ๊ฟ์น๊ธฐ' ์ค์ (์ฌ์ฉํ๋ ์ชฝ ์ฝ๋ ๋ณ๊ฒฝ X)
@Module({
providers: [
{
provide: 'EMAIL_SERVICE', // ์ด๋ฆํ
useClass: SendGridEmailService, // ์ค์ ์ธ ํด๋์ค (์ถํ ์ด๊ฑธ AwsEmailService๋ก ํ ์ค๋ง ๋ฐ๊พธ๋ฉด ๋!)
}
]
})์ฌ์ฉํ ๋๋ ์ปจํธ๋กค๋ฌ์์ @Inject('EMAIL_SERVICE') private emailService: IEmailService ๋ก ๋ฐ์ผ๋ฉด ๋ผ. ์ด๊ฑธ ์๋ฒฝํ ์ดํดํ๋ฉด ๋ ๋ ์ด์ ์ด๋ณด๊ฐ ์๋์ผ.
3. ์ํ ์์กด์ฑ ํด๊ฒฐ (Circular Dependency)
๊ฐ์ฅ ์ง์ฆ ๋๋ ์ํฉ: A ์๋น์ค๊ฐ B๋ฅผ ์ฃผ์ ๋ฐ๊ณ , B๊ฐ A๋ฅผ ๋ค์ ์ฃผ์ ๋ฐ๋ ์ํฉ. ๊ผฌ๋ฆฌ๋ฅผ ๋ฌด๋ ๋ฑ์ด์ง.
- **ํด๋ฒ 1 (๊ถ์ฅ):**A์ B๊ฐ ๊ณตํต์ผ๋ก ์์กดํ๋ C ์๋น์ค๋ฅผ ๋ง๋ค์ด์ ๋ถ๋ฆฌํ๋ค.
- ํด๋ฒ 2 (์ฝ๋ ์์ ): ๋ถ๋์ดํ๋ค๋ฉด
forwardRef๋ฅผ ์จ์ ํ๋ ์์ํฌ์ "์กฐ๊ธ๋ง ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ฃผ์ ํด์ค" ๋ผ๊ณ ๋ถํํ๋ค.
@Injectable()
export class ServiceA {
constructor(
@Inject(forwardRef(() => ServiceB))
private serviceB: ServiceB,
) {}
}๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
โ Nest can't resolve dependencies of the UsersController (?).
์ธ์ ๋์ค๋๊ฐ?
์ฑ์ ์ผฐ๋๋ฐ ํฐ๋ฏธ๋์ ์๋ป๊ฑด ๊ธ์จ๋ก ์ ๋ด์ฉ์ด ์ถ๋ ฅ๋๋ฉฐ ์๋ฒ๊ฐ ์ฃฝ์.
์์ธ:
์ปจํธ๋กค๋ฌ(์จ์ดํฐ)๊ฐ 1๋ฒ ํ๋ผ๋ฏธํฐ๋ก(0๋ฒ ์ธ๋ฑ์ค) ๋ฌด์ธ๊ฐ๋ฅผ ์ฃผ์
ํด๋ฌ๋ผ๊ณ ํ๋๋ฐ, ํด๋น ๋ชจ๋์ providers: [] ๋ฐฐ์ด์ ๊ทธ ํด๋์ค๊ฐ ๋น ์ ธ์์.
ํด๊ฒฐ์ฑ :
app.module.ts(๋๋ ํด๋น ๊ธฐ๋ฅ ๋ชจ๋) ์ด๊ธฐproviders: [UsersService]์ฒ๋ผ ๋ด๊ฐ ์ธ ์๋น์ค๋ฅผ ์ ๋๋ก ๋ฑ๋กํ๋์ง ์ฒดํฌ!
โ Maximum call stack size exceeded
์ธ์ ๋์ค๋๊ฐ?
์๋ฒ๋ฅผ ์ผ์๋ง์ ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ฉด์ ์น๋ช
์ ์ธ ์๋ฌ๋ฅผ ๋ฑ์.
์์ธ:
์์์ ๋งํ ์ํ ์ฐธ์กฐ ๋๋ฌธ์ด์ผ. Module A -> Module B -> Module A ๋ฌดํ ๋ฃจํ!
ํด๊ฒฐ์ฑ :
- ์ด๋ ๋ชจ๋๋ผ๋ฆฌ ๊ผฌ์๋์ง ํ์
(
forwardRef์ ์ฉํ๊ธฐ). - ๊ฐ์ฅ ์ข์ ๊ฑด ์ค๊ณ๋ฅผ ๊ณ ์ณ์ ์๋ฐฉํฅ ์์กด์ ๋จ๋ฐฉํฅ์ผ๋ก ์ชผ๊ฐ๋ ๊ฒ.
๐๏ธ ์นํธ์ํธ
- ๋จ์ ์๋น์ค ์ ์ธ:
@Injectable() export class MyService {} - ์์กด์ฑ ์ฃผ์
๋ฐ๊ธฐ:
constructor(private readonly appService: AppService) {} - ๋ชจ๋์ ๋ฑ๋กํ๊ธฐ:
@Module({ providers: [MyService] }) - ์ฑ๊ธํค ๋๊ธฐ:
@Injectable({ scope: Scope.REQUEST })
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๋น์ ์ด ๊ฐ๋ฐ ์ค์ธ OrderService์์ ์ฅ๋ฐ๊ตฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ํด CartService๋ฅผ ๊ฐ์ ธ๋ค ์ฐ๊ณ ์ถ๋ค. ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์?
- A)
cartService = new CartService();๋ผ๊ณ ์ง์ ํ ๋นํ๋ค. - B)
@Injectable()์๋์ ์์ฑ์ผ๋ก ์ ์ธํด๋๋ค. - C)
constructor(private readonly cartService: CartService) {}๋ฅผ ํตํด ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋๋ค.
โ ์ ๋ต: C
๐ก **์ค๋ช
:**NestJS์ ํต์ฌ ์ฒ ํ์ ์ ์ด์ ์ญ์ (IoC)! new ํค์๋๋ ์ ๋ ์ฐ์ง ๋ง๊ณ ์ง๋ฐฐ์ธ์๊ฒ ๋น๋นํ ์๊ตฌํ ๊ฒ.
Q2. ๋ค์ ์ค ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์์ธ์ ๋ฌด์์ธ๊ฐ?
@Injectable()
export class UserService {
constructor(private readonly authService: AuthService) {}
}
@Injectable()
export class AuthService {
constructor(private readonly userService: UserService) {}
}โ
์ ๋ต: ์ํ ์์กด์ฑ (Circular Dependency)
์ค๋ช
: ๋ญ๊ณผ ๋ฌ๊ฑ์ ๋ฌธ์ ์ง. ์ ์ ์๋น์ค๋ฅผ ๋ง๋ค๋ ค๋ค ๋ณด๋ ์ธ์ฆ์ด ํ์ํ๊ณ , ์ธ์ฆ์ ๋ง๋ค๋ ค๋ ์ ์ ๊ฐ ํ์ํด์ ๋ฌดํ ๋๊ธฐ์ ๋น ์ ธ. forwardRef๋ฅผ ์ฐ๊ฑฐ๋ ๊ณตํต ์๋น์ค๋ก ์ฐข์ด๋ด์ผ ํด!
Q3. UserService ํ์ผ์๋ @Injectable()์ ๋ฌ์๊ณ , ์ปจํธ๋กค๋ฌ์์๋ constructor๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ฃผ์
๋ฐ์๋ค. ๊ทธ๋ฐ๋ฐ๋ Nest can't resolve dependencies ์๋ฌ๊ฐ ๋๋ค๋ฉด, ์ด๋ค ํ์ผ์ ๋ฌด์จ ์ฝ๋๋ฅผ ๋นผ๋จน์ ๊ฒ์ผ๊น?
โ
์ ๋ต: user.module.ts ํ์ผ(ํด๋น ๋ชจ๋)์ @Module ๋ฐ์ฝ๋ ์ดํฐ ์ providers: [UserService] ๋ฐฐ์ด์ ๋ฑ๋กํ๋ ๊ฑธ ๊น๋จน์์!