블로그 이전했습니다~
링크(https://steemit.com/@cicada0014)
요즘 한창 타입스크립트를 이용해서 express 서버를 구축하고 있다.
(막간을 이용해서 홍보 /
천기new설 포스텔러)
코드리뷰를 받으면서 많이 부족함을 느꼈다.
나는 용어를 명확하 이해하지 않고 개발을 하고 있었는데, 용어 설정에 신중함을 기해야 겠다.
코드를 살펴보니 전체적으로 의존성 주입이 애매했다. 코드를 짜면서도 매번 매핑시켜주는 것이
귀찮아 지기 시작했는데, 시간없음을 핑계로 해당 라이브러리를 제대로 파악하지 않았다.
검색을 해보니
inversify.js 라는 훌륭한 라이브러리가 있었다. (타입스크립트도 지원되니 딱 알맞았다)
하지만 한국어로 된 포스팅은 없었다. 우리나라에서는 JAVA/Spring이 강세라서 그런건가
node express를 사용하시는 다른분들은 IOC를 어떻게 구현하실까
Vue js를 사용하시는 분이 inversify에 대한 포스팅을 해준 것이 구글 한글검색에서는 전부였다.
한글로된 2번째 inversify 관련 포스팅이라 생각하면서 작성해본다.
Spring을 써봤던 기억을 더듬고, Angular에서 의존주입하는 방식을 접목해서 구축해보았다. express
typescript가 널리 번창하기를 바라는 사용자로써 일조를 하고자한다.
해당 깃 리포지토리는 이 url로 클론하실 수 있습니다.
https://github.com/cicada0014/jwt-practice.git
inversify 홈페이지 가이드를 살펴본다.
npm install inversify reflect-metadata --save
inversify 말고 reflect-metadata 라는 것도 설치해야 함을 알 수 있다
이 포스트에서 다루고자 하는 내용을 벗어나므로 간단하게 설명하고 넘어간다.
컨테이너에 컴포넌트들을 등록하고 자동으로 주입을 하기 위해서는 컴포넌트의 내부를 들여다 보아야한
다.
Reflect라는 말의 의미는 한국어로는 비춰본다와 상통한다. 즉, 컴포넌트를 살펴보며 자동주입을 하기 위한 라이브러리이다
inversify는 typescript 2.0 이상을 지원한다. (@XXX 와 같은) decorator를 쓰기 위해서는
tsconfig.json을 손봐야한다.
{
"compilerOptions": {
"target": "es5",
"lib": ["es6", "dom"],
"types": ["reflect-metadata"],
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
위처럼 설정해주지 않으면 inversify를 사용할 수가 없다.
이제부터 express와 연동하는 간단한 예제를 만들어본다.
물론 express와 typescript가 설치되어 있어야 한다. 모르는 분은 이 부분을 참조
필자는 적당한 디렉토리로 가서 다음과 같이 명령어를 실행했다.
mkdir inversify-prac && cd inversify-prac && npm init - y && npm i inversify inversify-express-utils express reflect-metadata @types/node @types/express --save && tsc -init
이제 디렉토리에 node_modules와 package.json, tsconfig.json이 생성되어 있을 것이다.
tsconfig.json은 위에서 소개한대로 설정을 바꾸면 된다.
app.ts 파일을 만들고 다음과 같이 입력한다
주의할점이 하나 있다. reflect-metadata는 다른 것들보다 우선해서 import 되어야 한다 이 polyfill은 싱글턴으로 생성되는데 , 이 처럼 최상위 파일에 한번만 넣어주면 된다.
최종적으로 만들어지는 것은 express.Application 타입이다.
생성자 메소드를 보자
먼저 IOC 컨테이너를 생성한다. 그 컨테이너를 INversifyExpressServer에 파라미터로 넘겨주어 서버를 생성하고, 서버를 빌드시켜주면 express 서버가 만들어진다.
예시 컴포넌트를 2개 생성해본다.
웹어플리케이션이므로 컨트롤러아 모델을 하나씩 생성한다.
model.ts
@injectable 데코레이터를 클래스위에 명시한다. 이 데코레이터를 통해 컨테이너로 자동으로 등록이 된다. model은 hello 스트링값을 가진 value 프로퍼티를 지니고 있다.
container.ts
컨트롤러 역시 @injectable을 통해 컨테이거가 인식할수 있도록 해야한다.
@Controller 데코레이터는 이 ㅋ클래스가 컨트롤러이며, 경로값을 매핑할 수 있도록 해준다.
생성자 부분을 보면 @inject 데코레이터가 쓰이고있다. ㅇ이는 컨테이너에게 다음에 해당하는 식별자를 가진 컴포넌트를 주입해달라고 명령하는 부분이다. 모델이 자동주입되기때문에 model에 따로 값을 선언하지 않아도 사용이된다. @inject(Model.name) 부분에서 name에 대한 값은 Model 클래스의 이름값이다. 클래스이름 값이 유일무이 하기때문에 name값을 사용햇는데 name이 중첩된다면 다른 변수를 사용할 수도 있다.
inversify 가이드에서는 Symbol을 통해 유일값을 넣어주고 잇는데, 필자는 이 부분이 매우 귀찮은 부분이라 판단했다.
Model의 타입은 다음과 같다 new(...args)=>{} 생성자 리터럴이 그 타입이다.
이 생성자 함수에 자동으로 들어가 있는 name 값을 사용한 것인데 클래스이름과 동일하다.
생각을해보면 클래스의 이름은 유일한 값으로 등록하기 마련이다. 이미 유일한 식별자 값으로서 작동하고 있는 클래스의 이름을 사용하는 것이 유리하지 않을까? 물론 클래스에 name이라는 프로퍼티가 오버라이딩 될경우 의도했던 바가 나오지 않을 가능성이 있다. 이점은 개발자가 명확히 인지를 하고 있다면 문제될것이 없다고 판단하는데 초짜의 생각이므로.... 뭔가 단점이 있을 것 같다.
데코레이터를 달아 놓기만 해서는 컨테이너가 인식할수가 없다.
(스프링에서는 자동으로 주입되었던 것으로 기억한다)
this.container.bind(TYPE.Controller).to(ExempleController).whenTargetNamed(ExempleController.name)
this.container.bind<Model>(Model.name).to(Model).whenInjectedInto(ExampleController)
app.ts의 일부이다. 이렇게 bind 메소드를 써서 명시를 해줘야 한다.
bind 메소드에 들어가는 식별자 값은 @inject에서 사용되는 식별자 값과 일치해야한다.
컨트롤러의 경우 inversify-express-utils의 타입에서 식별자 값을 가져온다.
식별자값은 중복이 가능하다. 대신이 중복되더라도 원하는 값을 가져오기 위해서 to 메소드 다음에 when XXX 메소드를 덧붙여야 한다.
tsc && node ./app.js
위 명령어를 실행하면 서버가 작동된다.
이제 http://localhost:3000/hello/world에 들어가면 hello world! 가 나타나는 것을 볼 수 있다.
우리의 예측대로 자동주입이 잘 되었음을 의미한다.
Angular 처럼 사용하고자 하는 것들을 최상위 컨테이너에 등록을 해두고 해당 클래스에서 주입받고자하는 컴포넌트들만 기록을 하는 방법을 구현해보고자 했다.
예를들어 컨트롤러가 model1 뿐만 아니라 model2, model3 도 필요하다고 해보자.
개발자가 해주는 것은 model2, 3에 @injectable() 데코레이터를 붙여주고 컨테이너에 등록시켜준다.
컨트롤러에 model2 model3 를 inject 하고 싶다고 명시하기만 하면 된다.
어떤식으로 어떻게 들어오는지 컨트롤러는 알지 못한다. 컨테이너에서 설정해주는 것이다.
이 패턴을 이용하지 않았다면 개발자는 하나하나 매핑을 직접해주어야 했을 것이다.
컨트롤러 내부에 컨테이너를 생성해서 그 값을 직접 매핑시켜주거나 컨테이너에서 컨트롤러를 불러다가 생성시기에 매개변수로 넘겨주거나 하는 방식으로 말이다.
inversify 문서를 읽어보면 다양한 상황에서 매핑방식을 설정해줄수가 있다. 어떤 이름일때, 어떤 태그를 지니고 있을때, 어디에 주입되었을때만 바인딩이 되도록 설정할 수가 있다.
펌
답글삭제inversify의 문제는 버그가 너무많다는점.. 그리고 그문제가 해결이 안되고있다는점이네요.
답글삭제현재로선 view엔진이 사용이 불가능하며,
next로 error 객체가 안넘아가는 버그가 버젓히 존재하는데 2년째 안고치고있네요..