Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SECRET=
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
package-lock.json
.env
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:alpine

WORKDIR /usr/app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD [ "npm" , "start"]
92 changes: 60 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,60 @@
# Desafio BennuBR de Backend

Contrua uma API em NodeJS, que consultará o arquivo _news.json_ e disponibilizará as seguintes rotas:

- Rota para Login, retornando o _JWT_ que será utilizado nas requisições;
- Rota para Logout (rota autenticada com _JWT_);
- Rota para listar notícias (rota autenticada com _JWT_) no formato _JSON_;
- Rota para exibir o detalhe de uma notícia através do _ID_ (rota autenticada com _JWT_) no formato _JSON_;

## Requisitos
- Forkar esse desafio e criar o seu projeto (ou workspace) usando a sua versão desse repositório, tão logo acabe o desafio, submeta um pull request.
- O código precisa rodar em macOS ou Ubuntu (preferencialmente como container Docker)
- Para executar seu código, deve ser preciso apenas rodar os seguintes comandos:
- git clone \$seu-fork
- cd \$seu-fork
- comando para instalar dependências
- comando para executar a aplicação
- A API pode ser escrita com ou sem a ajuda de _frameworks_
- Se optar por usar um _framework_ que resulte em _boilerplate code_, assinale no README qual pedaço de código foi escrito por você. Quanto mais código feito por você, mais conteúdo teremos para avaliar.
- A API precisa suportar um volume de 1000 requisições por segundo em um teste de estresse.

## Critério de avaliação

- **Organização do código**
- **Clareza**
- **Assertividade**
- **Legibilidade do código**
- **Segurança**
- **Histórico de commits**
- **Escolhas técnicas**

Boa sorte e divirta-se!!!
Bennu TV
API desenvolvida para teste de técnico no processo seletivo da equipe Bennu TV.

Tecnologias / Metodologias, utilizadas no projeto:

- Node.js
- express.js
- docker
- nodemon
- GitFlow
- cluster
- Jwt

Pré-requisitos:

Antes de mais nada, verifique se você possui os requisitos para rodar o projeto.

- Docker-compose
- node
- npm

Instruções para instalação e configuração:

Essas instruções farão com que você tenha uma cópia do projeto em execução na sua máquina local para fins de desenvolvimento e teste.

Instalação
É bem simples, com 4 passos você conseguirá rodar o projeto em sua máquina. Veja:

1) Clone o projeto para sua máquina

git clone https://github.com/victorhugooleal/desafio-backend.git


2) Entre na pasta raiz do projeto que você acabou de clonar

cd desafio-backend

3) Rode o comando:

npm i

4) rode o comando:

docker-compose up

Pronto, a API estará rodando em http://localhost:3000

Para rodar o teste de Carga será necessário a instalação do artillery:

npm install -g artillery

para executar o teste basta executar o comando:

artillery run testeCarga.yml

Autor
Victor Leal - https://www.linkedin.com/in/victor-hugo-leal-46ba74105

Agradecimentos
Equipe Bennu TV, pela oportunidade.
44 changes: 44 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require("dotenv-safe").config();
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var newsRouter = require('./routes/news');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/news', newsRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;
18 changes: 18 additions & 0 deletions backlog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#TODO

[x] Rota para Login, retornando o _JWT_ que será utilizado nas requisições;
[x] Rota para Logout (rota autenticada com _JWT_);
[x] Rota para listar notícias (rota autenticada com _JWT_) no formato _JSON_;
[x] Rota para exibir o detalhe de uma notí

#Requisitos

[x] configurar projeto para rodar com docker(linux, macos)
[x] Para executar seu código, deve ser preciso apenas rodar os seguintes comandos:
- git clone \$seu-fork
- cd \$seu-fork
- docker-compose up

[] assinalar codigo gerado pelo framework
[] Criar teste de stress e anexar no projeto evidência de que o projeto aguenta 1000/rps
[x] criar teste automatico dentro do projeto
90 changes: 90 additions & 0 deletions bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('news:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3"

services:
news:
build: .
command: npm start
ports:
- "3000:3000"
volumes:
- .:/usr/app
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "news",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon --watch ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"dotenv": "^8.2.0",
"dotenv-safe": "^8.1.0",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"jsonwebtoken": "^8.5.1",
"md5": "^2.2.1",
"morgan": "~1.9.1",
"nodemon": "^1.19.4",
"pug": "2.0.0-beta11"
}
}
8 changes: 8 additions & 0 deletions public/stylesheets/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
color: #00B7FF;
}
9 changes: 9 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: '404' });
});

module.exports = router;
19 changes: 19 additions & 0 deletions routes/news.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require("dotenv-safe").config();
var express = require('express');
var router = express.Router();
var authentication = require('../utils/authentication');

//Mock news
const news = require("../static/data/news");

router.get('/list', authentication.verifyJWT, function(req, res) {
res.status(200).send(news);
});

router.get('/:id', authentication.verifyJWT, function(req, res) {
var id = req.params.id;
var searchedNews = news.find(obj => obj.id == id);
res.status(200).send(searchedNews);
});

module.exports = router;
41 changes: 41 additions & 0 deletions routes/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require("dotenv-safe").config();
var express = require('express');
var router = express.Router();
var md5 = require('md5');
var authentication = require('../utils/authentication');
var jwt = require('jsonwebtoken');

//Mock User
const user = require("../static/data/users");

router.post('/login', (req, res) => {
// Valida se ousuário é válido
if( user.login == req.body.user && user.pwd == md5(req.body.pwd)){

// Pega Id do usuário
const userId = user.id;

// Cria Token
const token = jwt.sign({ userId }, process.env.SECRET, {
expiresIn: "1 hour" // expires in 1 hour
});

// Retorna token
res.send({ auth: true, token: token });

}else{ // Retorna falso, id inválido
res.send({
auth: false,
message: 'Login inválido!'
});
}
});

router.get('/logout', authentication.verifyJWT, function(req, res) {
res.status(200).send({
auth: false,
token: null
});
});

module.exports = router;
2 changes: 1 addition & 1 deletion news.json → static/data/news.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@
"news_category_id": 2,
"publisher_media_2": "https://bobcontents.bennuapp.com.br/publisher_medias/correio_povo/logo-color.svg"
}
]
]
Loading