Conhecendo e implementando o InversifyJS

Como desenvolver uma API elegante com NodeJS — parte 2

Matheus Bessa
5 min readMay 9, 2020

Na teoria 📚👨🏻‍🎓👩🏼‍🎓

Desde o lançamento do ES6 em 2015, o Javascript vem disponibilizando diversas features que geraram força à linguagem, tornando-a muito mais competitiva no mercado. A própria declaração e uso de classes, lançado nessa época, trouxe uma abstração fantástica para quem quer abordar Princípios de Orientação a Objetos em seu código Javascript.

E visando esse tipo de adoção de código, nasce o InversifyJS com o intuito de viabilizar o melhor que aprendemos sobre as melhores práticas da Programação Orientada a Objetos. Então se você veio do Java, ou do .NET, vai se familiarizar com alguns princípios que essa ferramenta traz.

Filosofia do InversifyJS

Pelo fato do Inversify propor a viabilização de características conceituais da programação, como Inversão de Dependência (DIP), a ideia da ferramenta fica vasta podendo perder a sua identidade com o tempo. E por esse motivo foram criados 4 objetivos que a ferramenta deve alcançar.

Objetivos que eu acho relevante ressaltar, sendo eles:

  1. Possibilitar que os Desenvolvedores Javascript escrevam códigos aderentes aos Princípios SOLID.
  2. Facilitar e Estimular a adoção das melhores práticas de Orientação a Objetos e Inversão de Controle.
  3. Adicionar o mínimo de sobrecarga possível em tempo de execução. (Ou seja ele é leve - 4kb)
  4. Proporcionar um Ecossistema que dê a experiência de desenvolvimento de última geração ao desenvolvedor.
É um previlégio poder codar algo bacana com boas práticas

Na prática ⚡👨🏻‍💻👩🏼‍💻

Bom vamos lá, mão na massa pra gente ver se essa lib é boa mesmo. A princípio o único pré-requisito para o Inversify é o Typescript +2.0.

Pré-requisitos

1. Typescript +2.0.

2. Instale o inversify e o reflect-metadata:

npm install inversify reflect-metadata --save

3. Também há a necessidade de alguns ajustes nas configurações de compilação dentro do arquivo tsconfig.json. Sendo eles em negrito abaixo:

{
"compilerOptions": {
"target": "es5",
"lib": ["es6", "dom"],
"types": ["reflect-metadata"],
"pretty": true,
"sourceMap": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist",
"baseUrl": "./src",
"experimentalDecorators": true,
"emitDecoratorMetadata": true

},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

4. (opcional) É interessante que seu package.json esteja mais ou menos com esse formato, com essas dependências e scripts do npm:

{
"name": "02-inversify-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "tsc && node dist/app.js",
"lint": "npx eslint ./src/*.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"typescript": "^3.8.3",
"inversify": "^5.0.1",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.31.0",
"@typescript-eslint/parser": "^2.31.0",
"eslint": "^6.8.0"
}
}

Primeiros Passos

Temos que ter em mente que um dos objetivos dessa ferramenta é dar aderência ao SOLID no Javascript, e um dos Princípios do SOLID é a Inversão de Dependência, que indica que é preferível depender de abstrações não de implementações concretas.

Vamos iniciar criando as nossas Interfaces (abstrações) no Typescript:

Para que possamos depender de abstrações e tudo ocorra bem, é necessário que as dependências sejam injetadas em tempo de execução. E para isso o Inversify necessita de uma configuração de tipagem para a identificação do tipo em tempo de execução.

Segue a configuração:

Agora vamos para as implementações concretas com as nossas classes Pessoa e Sala. Reparem que as classes são decoradas por “@injectable”, que indica que a classe correspondente é injetável em tempo de execução. Outra coisa a se reparar, a classe Pessoa tem em seu construtor um parâmetro decorado com “@inject”, que realiza a injeção do SalaInterface nela.

Seguem as classes:

E por fim o nosso arquivo principal (app.ts), realiza o bind das nossas interfaces com nossas classes. E a reservaSalaTeste() realiza o teste dessa nossa implementação, mas vale notar que não declaramos uma instancia do zero de pessoa, mas aproveitamos o bind feito anteriormente, obtendo a mesma instancia, e assim trabalhamos com ela. Essa também é uma forma de obter a instancia da dependência sem injeta-la diretamente no construtor da sua classe.

Bora pro código:

E o Resultado…

Inversify + Express

Dentro do ecossistema do Inversify, existem alguns plugins e extensões que nos auxiliam na implementação em diversos contextos diferentes. Ja que vamos desenvolver uma API Restful, vamos utilizar o inversify-express-utils.

A instalação dessa extensão é via npm, sem nenhuma novidade:

npm install inversify-express-utils --save

Mas esse nosso exemplo tem algumas outras dependências que estão no package.json deste repositório que está no final desse artigo.

Criando o Server Express

A criação do Server no express é algo bem simples. Basicamente você cria uma instância de servidor com o InversifyExpressServer, dentro dele você insere o container que contêm os binds de injeção de dependência da sua aplicação, o mesmo explicado anteriormente.

É importante que você importe as controllers da sua aplicação dentro do app.ts, para que o inversify-express-utils reconheça as classes que representam as suas rotas/endpoints.

Bom segue o app.ts e o types.ts:

Controllers e Services

Bom como dito anteriormente, as controllers representam as nossas rotas/endpoints da nossa API Restful. Ela tem uma implementação bem amigável com o decorador “@controller” para a classe, e decoradores de “@httpGet”, “@httpPost”, “@httpPut”, etc, para os métodos que implementarão os endpoints.

Além de ser decorado por “@controller” a classe necessita da implementação da interface de Controller. E se prefirir, é interessante extender para sua controller a classe BaseHttpController. (Classe que proporciona diversos recursos que auxiliam na manipulação de requisição/resposta de seu controller).

Já o service, nesse contexto, tem o papel de ter a regra de negócio mesmo. Sem muita implementação complexa, nesse exemplo ele só retorna um string “OK” para validar a implementação do Express. Não há nada de diferente do que foi explicado no artigo anterior, mas mesmo assim segue o código:

Testando

Bora provar que funciona né? rs…

Conclusão

É interessante o quanto o Inversify pode nos ajudar no cumprimento de princípios de desenvolvimento, além de fornecer todo um ecossistema que condiciona essa implementação em contextos diferentes.

Vale a pena ler a documentação e ver outras features disponíveis na ferramenta.

Abaixo temos os repositórios dos 2 exemplos citados nesse artigo:

Então é isso aih! Vlw, Flws!

--

--