Conhecendo e implementando o InversifyJS
Como desenvolver uma API elegante com NodeJS — parte 2
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:
- Possibilitar que os Desenvolvedores Javascript escrevam códigos aderentes aos Princípios SOLID.
- Facilitar e Estimular a adoção das melhores práticas de Orientação a Objetos e Inversão de Controle.
- Adicionar o mínimo de sobrecarga possível em tempo de execução. (Ou seja ele é leve - 4kb)
- Proporcionar um Ecossistema que dê a experiência de desenvolvimento de última geração ao desenvolvedor.
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!