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 .

vs1

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

vs2

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

vs3

agora abrir o arquivo package.json e criar o script para execução do código .

vscd1

adicionando essa linha de scripts com o nome de "dev" e build ' já podemos executar o comando abaixo

yarn dev

vsss2

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

nodemon

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.

nodemoncfg

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.

nodemon2

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 :

eslintcfg

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

es1

agora em edit settings.json

es2

editar o arquivo json ele deverá ficar igual ao da imagem para o funcionamento desejado

es3

    "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

eslintok

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.

errroexpress

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

mongo1

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 .

docker2

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('User', UserSchema) o mode do export precisa extender para Userinterface igual na estrutura do codigo , esse é um padrão do moongose

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 a response seria o return res,json(users)

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"
}

insomina

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.

get

agora se abrir o link http://localhost:1024/users deverá abrir a lista no browser . no caso eu mandei o post varias vezes

mongofim

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

https://github.com/FranciscoBSpadaro/node-nodemon

Comentários