๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ‘จ‍๐Ÿ’ป web.dev/node

TypeDI ๋ฅผ ํ™œ์šฉํ•œ ์˜์กด์„ฑ ์ฃผ์ž…

by HandHand 2022. 5. 28.

๐Ÿ“Œ TypeDI ๋ž€?

typeDI ๋Š” Typescript์™€ Javascript ์˜ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž… ์„ ํ†ตํ•ด OOP ์•„ํ‚คํ…์ณ์˜ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ๊ตฌ์กฐ๋ฅผ ๊ฒฌ๊ณ ํžˆ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ด๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ๊ฐ์˜ service ์™€ controller layer ์˜ ๊ตฌ์กฐ๋ฅผ ์žก์œผ๋ ค ํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ํŒจํ‚ค์ง€ ์„ค์น˜

๋จผ์ € typeDI ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

$ npm i typedi reflect-metadata

typeDI ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— tsconfig.json ์—์„œ ๋‹ค์Œ ์„ค์ •์„ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

"emitDecoratorMetadata": true,
"experimentalDecorators": true,

 

๐Ÿ“Œ Node.js + TypeDI ์ ์šฉ ์˜ˆ์‹œ

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ๋‚ด์—์„œ๋Š” ์ตœ ์ƒ๋‹จ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด reflect-metadata ๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Express.js ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— app.ts ์—์„œ ์ด๋ฅผ ๋ถˆ๋Ÿฌ ์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค.

// app.ts

import 'reflect-metadata'

 

์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•œ ์‚ฌ๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์šฐ์„  ๋‹‰๋„ค์ž„์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ service ๊ณ„์ธต ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Service ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํด๋ž˜์Šค๊ฐ€ ์ธ์Šคํ„ด์Šคํ™” ๋  ์ˆ˜ ์žˆ๋„๋ก ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

// services/nickname.ts

import { Service } from 'typedi';

@Service()
class NicknameService {
  public constructor() {
    // ...
  }

  public createNickname() {
    // ... nickname ์ƒ์„ฑํ•˜๊ณ 

    return nickname;
  }
}

export default NicknameService;

 

์ดํ›„ controller ๊ณ„์ธต์—์„œ ์œ„ ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๋•Œ๋Š” Container.get ์„ ์ด์šฉํ•ด์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// controllers/nickname.ts

import { Container } from 'typedi';
import { Request, Response, NextFunction } from 'express';
import NicknameService from '@/service/nickname';

export const getRandomNickname = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const nicknameService = Container.get(NicknameService);

  res.status(200).json({
    message: '๋žœ๋ค ๋‹‰๋„ค์ž„ 1๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.',
    data: {
      nickname: nicknameService.createNickname(),
    },
  });
};

์œ„์—๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ผ ํ™œ์šฉ๋˜์ง€ ์•Š์•˜์ง€๋งŒ ๋งŒ์•ฝ ํด๋ž˜์Šค ๊ฐ„์— ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด

Inject ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ’ก Inject ํ™œ์šฉ ๋ฐฉ๋ฒ• (/w Typescript)

ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•œ Inject ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ™œ์šฉ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ์ปค์Šคํ…€ ํด๋ž˜์Šค๋ฅผ ์ฃผ์ž… ๋Œ€์ƒ์œผ๋กœ ํ™œ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด Container ์— ๋“ฑ๋ก ํ•ด์ค๋‹ˆ๋‹ค.

// databases/redis/index.ts

import { Container } from 'typedi';

class RedisClient {
    // ...
}

Container.set('nicknameDB', new RedisClient());

 

์ด์ œ nicknameDB ๋ผ๋Š” ๋„ค์ž„ ์ŠคํŽ˜์ด์Šค๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ์œ„ ํด๋ž˜์Šค๋ฅผ ์˜์กด์„ฑ ํ•ญ๋ชฉ์œผ๋กœ ์ง€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// service/nickname.ts

import { Service, Inject } from 'typedi';
import RedisClient from '@/databases/redis';

@Service()
class NicknameService {
  @Inject('nicknameDB') nicknameDB!: RedisClient;
    // ...
}

 

๐Ÿ“Œ ์ฐธ๊ณ  ์ž๋ฃŒ

TypeScript์™€ typedi๋กœ ์˜์กด์„ฑ ์ฃผ์ž… ์ดํ•ดํ•˜๊ธฐ

Getting Started

๋ฐ˜์‘ํ˜•

๐Ÿ’ฌ ๋Œ“๊ธ€