Crie uma pasta como o nome do projeto (mkdir nome-projeto)
Entre na pasta e inicie o Git
git init
Criar o arquivo .gitignore (touch .gitignore)
node_modules
.env
Execute os comandos abaixos (você precisará do Yarn)
yarn init -y
yarn add express
yarn add sucrase nodemon -D
Crie o arquivo src/routes.js
import { Router } from "express";
const routes = new Router();
routes.get("/", (req, res) => {
return res.json({ status: "on-line" });
});
export default routes;
Crie o arquivo src/app.js
import express from "express";
import routes from "./routes";
class App {
constructor() {
this.server = express();
this.middlewares();
this.routes();
}
middlewares() {
this.server.use(express.json());
}
routes() {
this.server.use(routes);
}
}
export default new App().server;
Crie o arquivo src/server.js
import app from "./app";
app.listen(3333);
Crie o arquivo nodemon.json
{
"execMap": {
"js": "sucrase-node"
}
}
Acresente no arquivo package.json
"scripts": {
"dev": "nodemon src/server.js"
}
Execute o comando
yarn add dotenv
Crie o arquivo .env
APP_URL= http://localhost:3333
NODE_ENV=development
Inclua no arquivo src/app.js
import 'dotenv/config';
Execute os comandos abaixo
yarn add eslint -D
yarn eslint --init
Selecione
- To check syntax, find problems, and enforce code style
- JavaScript modules (import/export)
- None of these
- Marque somente Node
- Use a popular style guide
- Airbnb (https://github.com/airbnb/javascript)
- Javascript
- Y
Ao terminar, exclua o arquivo package-lock.json e execute os comandos
yarn
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
Crie o arquivo .prettierrc
{
"singleQuote": true,
"trailingComma": "es5"
}
Altere o arquivo .eslintrc.js
module.exports = {
env: {
es6: true,
node: true,
},
extends: ['airbnb-base', 'prettier'],
plugins: ['prettier'],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
'prettier/prettier': 'error',
'class-methods-use-this': 'off',
'no-param-reassign': 'off',
camelcase: 'off',
'no-unused-vars': ['error', { argsIgnorePattern: 'next' }],
},
};
No VSCode, clique com botão direito e selecionar a opção generate .editorconfig
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
Para corrigir todos arquivos (indentação)
yarn eslint --fix src --ext .js
Execute os comandos
yarn add youch
yarn add express-async-errors
Iremos utilizar também o Sentry
Faça login com sua conta, crie um projeto e siga tutorial.
Exemplo
yarn add @sentry/node@5.5.0
Adcione ao arquivo .env
# Sentry
SENTRY_DSN='https://6b1a0c46525042f491a188aba36f68be@sentry.io/1511984'
A url é mesma que mostra no seu projeto no Sentry. Exemplo: Sentry.init({ dsn: 'https://6b1a0c46525042f491a188aba36f68be@sentry.io/1511984' });
Crie o arquivo src/config/sentry.js
export default {
dsn: process.env.SENRTY_DSN,
};
Inclua no arquivo src/app.js
import Youch from 'youch';
import * as Sentry from '@sentry/node';
import 'express-async-errors';
import sentryConfig from './config/sentry';
...
Sentry.init(sentryConfig);
...
this.exceptionHandler();
...
this.server.use(Sentry.Handlers.requestHandler());
...
this.server.use(Sentry.Handlers.errorHandler());
...
exceptionHandler() {
this.server.use(async (err, req, res, next) => {
if (process.env.NODE_ENV === 'development') {
const errors = await new Youch(err, req).toJSON();
return res.status(500).json(errors);
}
return res
.status(500)
.json({ error: 'Oops! Occoreu um erro no servidor!' });
});
}
Banco de dados (Docker com Postgres)
Após instalar o Docker, execute o comando:
docker run --name nome-do-container -e POSTGRES_PASSWORD=senha-acesso -p 5432:5432 -d postgres
Você pode usar o Postbird para criar o banco via interface (Gui)
Execute os comandos
yarn add sequelize
yarn add sequelize-cli -D
Crie o arquivo .sequelizerc
const { resolve } = require('path');
module.exports = {
config: resolve(__dirname,'src', 'config', 'database.js'),
'models-path': resolve(__dirname,'src', 'app', 'models'),
'migrations-path': resolve(__dirname,'src', 'database', 'migrations'),
'seeders-path': resolve(__dirname,'src', 'database', 'seeds'),
}
Se estiver utilizando o Postgres, excute também
yarn add pg pg-hstore
Adcione ao arquivo .env
# Database
DB_HOST=localhost
DB_USER=postgres
DB_PASS=senha-acesso
DB_NAME=nome-do-seu-banco
Crie o arquivo src/config/database.js
require('dotenv/config');
module.exports = {
dialect: 'postgres',
host: process.env.DB_HOST,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
define: {
timestamps: true,
underscored: true,
underscoredAll: true,
},
};
Crie o arquivo src/database/index.js
import Sequelize from 'sequelize';
import databaseConfig from '../config/database';
const models = [];
class Database {
constructor() {
// conexão com o banco de dados
this.connection = new Sequelize(databaseConfig);
this.init();
this.associate();
}
init() {
models.forEach(model => model.init(this.connection));
}
associate() {
models.forEach(
model => model.associate && model.associate(this.connection.models)
);
}
}
export default new Database();
Crie a pasta src/database/migrations
Execute o comando
yarn sequelize migration:create --name=create-users
Exemplo do arquivo migration-create-users
Para criar a tabela users no banco de dados use o comando
yarn sequelize db:migrate
Para desfazer use o comando
yarn sequelize db:migrate:undo
Para criptografia iremos utilizar o bcryptjs
yarn add bcryptjs
Para as validações iremos utilizar o Yup
yarn add yup
Crie o model src/app/models/User.js
Crie o Controller src/app/controllers/UserController.js
Inclua as rotas no arquivo src/routes.js
routes.post('/users', UserController.store);
routes.put('/users', UserController.update);
Inclua no arquivo src/database/index.js
import User from '../app/models/User';
...
const models = [User];
Execute o comando
yarn add jsonwebtoken
Adcione ao arquivo .env
# Auth
APP_SECRET=9f14070c64a04b5144ff59f42d4edf7b
Chave gerada no site https://www.md5online.org/
Crie o arquivo src/config/auth.js
export default {
secret: process.env.APP_SECRET,
expiresIn: '30d',
};
Crie um middleware (src/src/app/middlewares/auth.js)
import jwt from 'jsonwebtoken';
import { promisify } from 'util';
import authConfig from '../../config/auth';
export default async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ error: 'Token não informado!' });
}
const [, token] = authHeader.split(' ');
try {
const decoded = await promisify(jwt.verify)(token, authConfig.secret);
req.userId = decoded.id;
return next();
} catch (err) {
return res.status(401).json({ error: 'Token inválido!' });
}
};
Crie um Controller src/app/controllers/SessionController.js
import jwt from 'jsonwebtoken';
import * as Yup from 'yup';
import User from '../models/User';
import authConfig from '../../config/auth';
class SessionController {
async store(req, res) {
const schema = Yup.object().shape({
email: Yup.string()
.email()
.required(),
password: Yup.string().required(),
});
if (!(await schema.isValid(req.body))) {
return res.status(400).json({ error: 'Validação falou!' });
}
const { email, password } = req.body;
const user = await User.findOne({ where: { email } });
if (!user) {
return res.status(401).json({ error: 'E-mail não encontrado!' });
}
if (!(await user.checkPassword(password))) {
return res.status(401).json({ error: 'Senha inválida' });
}
const { id, name } = user;
return res.json({
user: {
id,
name,
email,
},
token: jwt.sign(
{
id,
},
authConfig.secret,
{
expiresIn: authConfig.expiresIn,
}
),
});
}
}
export default new SessionController();
Inclua no arquivo src/routes.js
import SessionController from './app/controllers/SessionController';
import authMiddleware from './app/middlewares/auth';
...
routes.post('/sessions', SessionController.store);
routes.use(authMiddleware);
Veja aqui