15 de abril de 2021 • 14 min de leitura
Nodejs + TypeScript
TypeScript, Sucrase, ESLint, Express, MongoDB, Mongoose e outras ferramentas
Projeto de um simples app para aprendizado
Esse é um tutorial de passo a passo explicando como desenvolvi meu primeiro projeto de estudo com nodejs e typescript.
Parte 1 - stack de módulos e ferramentas utilizadas
Nodejs - https://nodejs.org/en/
Node.js é um software de código aberto, multiplataforma, que executa códigos JavaScript no backend/servidor e frontend/interface, baseado no V8 interpretador de JavaScript em C++ do Google, mantido pela fundação Node.js em parceria com a Linux Foundation
Typescript - https://www.typescriptlang.org/
TypeScript é um superconjunto de JavaScript desenvolvido pela Microsoft que adiciona tipagem e alguns outros recursos a linguagem. Anders Hejlsberg, arquiteto da linguagem C# e criador das linguagens Delphi e Turbo Pascal, trabalhou no desenvolvimento do TypeScript
Nodemon - https://www.npmjs.com/package/nodemon
Nodemon é uma ferramenta que ajuda a desenvolver aplicativos baseados em node.js, reiniciando automaticamente o aplicativo de nó quando mudanças de arquivo no diretório são detectadas. O nodemon não requer nenhuma mudança adicional em seu código ou método de desenvolvimento. Nodemon é um invólucro substituto para o nó. Para usar o nodemon, substitua a palavra node na linha de comando ao executar seu script.
Sucrase - https://github.com/alangpierce/sucrase
O Sucrase é uma alternativa ao Babel que permite um desenvolvimento muito rápido. O Sucrase assume que você está desenvolvendo em um navegador recente ou em uma versão recente do Node.js, acelerando a sua experiência em desenvolvimento.
Ele se concentra na compilação de extensões da linguagem não-padrão, como JSX, TypeScript e Flow.
- O Sucrase não verifica se há erros no seu código, ele apenas produz código JS válido. Sempre verifique o código que você irá fornecer;
- Ele também não produz código para navegadores antigos;
- Não é um verificador de letras, ou seja, processa cada arquivo isoladamente.
- É benéfico principalmente no desenvolvimento mas, às vezes, Babel será mais adequado para compilações de produção.
O Sucrase visa o desenvolvimento de builds. Obtém ganhos de velocidade significativos provenientes de uma redução no escopo dos objetivos do compilador.
Prettier - https://prettier.io/
- ESLint: Responsável por identificar padrões de código em desacordo com as regras pré-estabelecidas.
- Prettier: Responsável por formatar o código de acordo com essas regras.
Eslint - https://eslint.org/
O ESLint analisa estaticamente seu código para encontrar problemas rapidamente. ESLint é integrado à maioria dos editores de texto e você pode executar o ESLint como parte de seu pipeline de integração contínua.
Express - https://expressjs.com/pt-br/
O Express é um framework para aplicativo da web do Node.js mínimo e flexível que fornece um conjunto robusto de recursos para aplicativos web e móvel.
Com uma Variedade de métodos utilitários HTTP e middleware a seu dispor, para criar uma API robusta é rápido e fácil.
MongoDB - https://www.mongodb.com/
MongoDB é um software de banco de dados orientado a documentos livre, de código aberto e multiplataforma, escrito na linguagem C++. Classificado como um programa de banco de dados NoSQL, o MongoDB usa documentos semelhantes a JSON com esquemas ' Schemas '
Mongoose - https://mongoosejs.com/
Mongoose é uma ferramenta de modelagem de objetos MongoDB projetada para funcionar em um ambiente assíncrono. O Mongoose oferece suporte a promessas 'Promise ' e retornos de chamada.
Docker - https://www.docker.com/
se você não sabe nada de docker já recomendo assistir ao vídeo.
Docker é um conjunto de produtos de plataforma como serviço que usam virtualização de nível de sistema operacional para entregar software em pacotes chamados contêineres. Os contêineres são isolados uns dos outros e agrupam seus próprios softwares, bibliotecas e arquivos de configuração.
Cors - https://www.npmjs.com/package/cors
CORS é um pacote node.js para fornecer um middleware Connect / Express que pode ser usado para habilitar CORS com várias opções.
Insomnia - https://insomnia.rest/download
Comece a construir, projetar e testar melhores APIs por meio do desenvolvimento de especificações conduzidas por pipelines de CI / CD APIOps.
Parte 2 - Iniciando o Projeto
esse app consiste em se comunicar com o banco de dados mongodb instalado no docker utilizando o Insomnia para enviar metodos GET/POST no formato json para inserir as informações no banco de dados.
o projeto vai usar o Eslint que irar corrigir os erros de endentação no código junto com o prettier .
o sucrase ira converter o código typescript para javascript para o ambiente de produção / build
Antes de iniciar lembre de instalar o nodejs , apenas baixe e instale
Crie uma pasta para o projeto , vamos usar o yarn para instalar os módulos e dependências do projeto
yarn init -y
criado o packge.json
O package.json
é um arquivo de configuração utilizado para estipular e configurar dependências do seu projeto (quais outros pacotes ele vai precisar para ser executado) e scripts automatizados. Através dele conseguimos deixar claro uma "receita" para executar um projeto.
Abra o vscode e selecione a pasta do projeto , abra o terminal e instale a primeira dependência .
yarn add -D typescript sucrase
toda linha de comando com o -D significa uma dependência de Developer ou apenas modo de desenvolvimento. módulos que não vão ser usados em produção
criar a pasta src ' source ' do projeto com o nome index.js para começar a fazer os teste
mkdir src
touch src/index.ts
obs esses comandos rápidos para criar arquivo como o touch só funciona se selecionar o terminal gitbash no terminal padrão windows ele não funciona. se não tiver o gitbash instalado cria a pasta manualmente , o gitbash vem junto com o git para versão windows.
no arquivo index colocar o código abaixo para teste , obs ao salvar esse código o eslint iria converter ele para um código mais limpo. mas ainda não configuramos o eslint. depois veremos como vai ficar o código toda vez que salvar um arquivo e o eslint corrigir automaticamente
agora abrir o arquivo package.json e criar o script para execução do código .
adicionando essa linha de scripts com o nome de "dev" e build ' já podemos executar o comando abaixo
yarn dev
se apareceu o numero 5 no terminal tudo certo até aqui !!
podemos observar que utilizando o sucrase o código executou bem rápido .
Agora vamos instalar o nodemon para iniciar o monitoramento automático do projeto
yarn add -D nodemon
apos instalado criar um arquivo na pasta principal como o nome nodemon.json
com esses parametros
watch é a pasta onde o nodemon vai monitorar
ext é a extensão a ser monitorada no caso ts é typescript , todo aquivo ts é monitorado suas modificações
execmap ele define quando um arquivo da extensao ts for atualizado qual script ira rodar.
mude o nome do arquivo index.ts para server.ts
já atualize também o arquivo package.json o script dev para server.ts
"scripts": {
"dev": "nodemon src/server.ts", }
já podemos também configurar o build caso futuramente queira testar o build
"build": "sucrase ./src -d ./dist --transforms typescript,imports" obs no github do sucrase podemos ver os transforms que ele dispõe , nesse caso ele transforma o typescript para javascript e importar o código na pasta dist onde vai ter o código javascript de todo o projeto -d significa diretório
agora podemos testar o nodemon executando novamente yarn dev , pode executar também yarn build para ver a pasta dist ser criada com o código convertido para js.
dessa forma o nodemon já está em funcionamento.
agora vamos configurar o eslint .
abra o terminal pelo vscode na pasta do projeto e execute
yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
após concluir a instalação executar o comando de configuração inicial
yarn eslint --init
no console vai abrir perguntas de configuração inicial.
usar essa opções :
* To check syntax, find problems, and enforce code style
* Javascript modules (import/export)
* None of These
* agora usando espaço desmarque browser e marque node e de enter
* Use a Popular Style Guide
* Standard
* Javascript
selecionada essa opçao vai iniciar a instalação
Importante o eslint está usando o npm para instalar e não o yarn , sendo assim ao concluir a instalação excluir o arquivo package.lock.json e rodar um ' yarn ' para captar as novas dependências que foi para um json do npm.
foi criado um arquivo .eslintrc.js ele deve estar configurado da maneira conforme o print :
module.exports = {
env: {
es2021: true,
node: true
},
extends: [
'standard',
'plugin:@typescript-eslint/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 12,
sourceType: 'module'
},
plugins: ['@typescript-eslint'],
rules: {}
}
agora se já nao tiver instalado instale a extensão do eslint no vscode
após instalado clique no ícone de engrenagem e selecione a opção extension Settings
agora em edit settings.json
editar o arquivo json ele deverá ficar igual ao da imagem para o funcionamento desejado
"workbench.editor.enablePreview": false,
"eslint.packageManager": "yarn",
"eslint.nodePath": "",
"eslint.trace.server": "messages",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"prettier.useEditorConfig": false,
"prettier.requireConfig": true,
"workbench.iconTheme": "vscode-icons",
"eslint.codeAction.showDocumentation": {
"enable": true
}
}
esses são os parâmetros atuais para configurar o eslint , antigamente era necessário abrir os settings do vscode e usar outros parâmetros , com esses parâmetros ao salvar um arquivo ele vai corrigir automaticamente arquivos de javascript e typescripts , quando abrir esse arquivo de configurações só vai ser necessário adicionar essas linhas
"eslint.trace.server": "messages",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
ao salvar essa configuração o eslint ja vai começar a apontar as correções
agora o eslint ja avisou os erros no codigo deixando ele mais limpo seguindo os padrões configurados , deixando o código sem necessidade de especificar o tipo da variável , sem necessidade de uma tipagem forte no código
Instalando o Prettier
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
agora basta instalar o prettier na extensão do vscode e agora toda vez que um código ficar fora do padrão do eslint ao salvar o código o prettier vai corrigir automaticamente
Agora com toda nossa estrutura de desenvolvimento pronta podemos começar nosso aplicativo !!
na pasta src criar arquivo app.ts
instalar as dependencias do app.
yarn add express cors mongoose
agora no app.ts importar o express.
agora o vscode indicou um erro com 3 pontinhos brancos ali no express , esse erro significa que não instalamos uma dependencia de tipos para o express , é necesarrio um pacote / lib para o express funcionar no typescript
instalando o types do express no modo developer - D e também para os outros módulos que vão precisar de types
yarn add @types/express @types/cors @types/mongoose -D
agora vamos importar os modulos e utilizar uma classe o typescript se integra muito bem com classe pois adiciona muitas funcões.
import express from 'express'
import cors from 'cors'
import mongoose from 'mongoose'
class App {
public express: express.Application
public constructor () {
this.express = express()
this.middlewares()
this.database()
this.routes()
}
private middlewares (): void {
this.express.use(express.json())
this.express.use(cors())
}
private database (): void {
mongoose.connect('mongodb://localhost:27017/tsnode', {
useNewUrlParser: true,
useUnifiedTopology: true
})
}
private routes (): void {
this.express.get('/', (req, res) => {
return res.send('hello world')
})
}
export default new App().express
public express: classe publica com o nome express e definindo o tipo dela como express.Application e construtor publico
private middlewares (): void { o retorno precisa ser declarado , então usamos void de vazio para pode criar a classe e a classe privado só pode ser acessado por dentro da classe
this.express.use(express.json()) this.express.use(cors()) usamos this. e use . para informar a classe que ela vai usar um arquivo json e o cors que é uma api na sua função
private database (): void { mongoose.connect('mongodb://localhost:27017/tsnode',
agora fazemos o mongoose se conectar no nosso banco de dados que está em funcionamento no docker.
useNewUrlParser: true, useUnifiedTopology: true são os parâmetros atuais que o mongoose precisa para acessar o banco de dados e não ter erros
opa vc ainda não instalou o docker?
baixe e instale o docker , inicie o docker , abra o cmd do windows e execute o comando
docker pull mongo
apos terminar executar
docker run --name my_mongo -p 27017:27017 -d mongo
o docker vai iniciar o mongo db com a porta 27017 liberada
apos executar os comandos o mongo db vai estar rodando, já é possivel clicarm abrir no browser e ver que esta funcionando.
podemos abrir a interface de linha de comandos dele e criar a pasta tsnode que colocamos no link do codigo .
podemos clicar na opção cli e vai abrir o console do mongodb , podemos digitar mkdir tsnode para criar a pasta tsnode e depois digitar ls e ver as pastas criadas .
continuando o entendimento do codigo
private routes (): void { this.express.get('/', (req, res) => { return res.send('hello world') metodo get no express para pegar o req e res request e response do express e retorna um hello word na tela , nesse caso o metodo get ele ja resonheceu a função req e res automaticamente porem isso nao vai acontecer sempre logo veremos uma necessidade de tipagem manual do req e res .
this.middlewares() this.database() this.routes() precisa ser declarado para chamar os metodos no arquivo server.ts
depois exportamos o codigo.
agora no arquivo sever.ts colocamos o codigo :
import app from './app'
app.listen(1024)
importamos o app.ts e usamos a porta 1024 porque qualquer porta acima dessa pode estar bloqueada no seu windows entao portas abaixo de 1024 funciona.
executamos yarn dev e vamos acessar
localhost:1024 e vemos o hello word
entao tudo funcionando até aqui . agora vamos trabalhar no banco de dados .
Criando os Schemas que são as estruturas do banco de dados
criando o schema usuario
criar pasta schemas dentro de src com arquivo User.ts
import { Schema, model, Document } from 'mongoose'
interface UserInterface extends Document {
email ?: string
firstName ?: string
lastName ?: string
fullName (): string
}
const UserSchema = new Schema({
email: String,
firstName: String,
lastName: String
}, {
timestamps: true
})
UserSchema.methods.fullName = function (): string {
return this.firstName + ' ' + this.lastName
}
export default model<UserInterface>('User', UserSchema)
começamos importando os metodos do moongose Schema, model, e Document.
Document
Os documentos do Mongoose representam um mapeamento individual para documentos armazenados no MongoDB. Cada documento é uma instância de seu modelo.
Document e Model são classes distintas no Mongoose. A classe Model é uma subclasse da classe Document. Ao usar o construtor Model, você cria um novo documento.
schema é a estrutura do banco de dados .
interface UserInterface extends Document , é necessário criar uma interface do javascript que é uma forma de falar qual a tipagem de um objeto de uma estrutura . com a estrutura com email firtstname etc.. ele é necessário para não perder os metodos qual for requisitado nos próximos codigos que vamos criar
const UserSchema = new Schema({ é o metodo que vai gerar a estrutura do banco de dados em si
UserSchema.methods.fullName = function (): string { return this.firstName + ' ' + this.lastName é uma formula para reprodutir o fullName
ao usar console.log(fullName) devera aparecer o nome completo.
export default model
Agora criar a pasta controllers dentro de src com o arquivo UserControllers.ts
import { Request, Response } from 'express'
import User from '../schemas/User'
class UserController {
public async index (_req: Request, res: Response): Promise<Response> {
const users = await User.find()
return res.json(users)
}
}
export default new UserController()
nesse código foi necessário importar o Request e Response do express pois o req e res nao foi reconhecido
import User from '../schemas/User' < importando todos os usuarios do banco de dados
o retorno da função tem que quer uma promise pois é async e a promise recebe um tipo de argumento
agora para testar vamos na pasta src e criar o arquivo de rotas routes.ts
import { Router } from 'express'
import UserController from './controllers/UserControllers'
const routes = Router()
routes.get('/users', UserController.index)
routes.post('/users', UserController.store)
export default
Com o código acima vamos agora importar as rotas no app.ts
import express from 'express'
import cors from 'cors'
import mongoose from 'mongoose'
import routes from './routes'
class App {
public express: express.Application
public constructor () {
this.express = express()
this.middlewares()
this.database()
this.routes()
}
private middlewares (): void {
this.express.use(express.json())
this.express.use(cors())
}
private database (): void {
mongoose.connect('mongodb://localhost:27017/tsnode', {
useNewUrlParser: true,
useUnifiedTopology: true
})
}
private routes (): void {
this.express.use(routes)
}
}
export default new App().express
agora ao voltar para http://localhost:1024/users devera aparecer um array vazio []
entao agora vamos criar um método de criaçao de usuário no UserControllers.ts
import { Request, Response } from 'express'
import User from '../schemas/User'
class UserController {
public async index (_req: Request, res: Response): Promise<Response> {
const users = await User.find()
return res.json(users)
}
// criar usuário
public async store (req: Request, res: Response): Promise<Response> {
const user = await User.create(req.body)
console.log(user.fullName)
return res.json(user)
}
}
export default new UserController()
agora vamos testar no Insomnia já que as rotas já estão configuradas .
no Insomina criar um metodo get e post
no post escolher json e colocar essa estrutura json
{
"email": "francisco.spadaro@outlook.com",
"firstName": "Francisco",
"LastName": "Spadaro"
}
ao clicar em send vai aparecer no preview a resposta mostrando que está funcionando
o get nao precisar ter nada no corpo. basta clicar em send e vai exibir os dados json do banco.
agora se abrir o link http://localhost:1024/users deverá abrir a lista no browser . no caso eu mandei o post varias vezes
obs se vc percebeu o console.log(user.fullName) do arquivo UserControllers.ts não está sendo exibido no terminal , isso ainda preciso descobrir como resolver.
isso é tudo !!
código completo no github