├── .gitignore ├── README.md ├── api ├── recommendation │ ├── recommendation.js │ └── recommendationService.js └── register │ ├── register.js │ └── registerService.js ├── config ├── cors.js ├── database.js ├── routes.js └── server.js ├── loader.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | package-lock.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.. 3 | 4 | Pré requisito: 5 | * NodeJS - https://nodejs.org/en/download/ 6 | * MongoDB - https://www.mongodb.com/try/download/community2 7 | 8 | # Getting Started 9 | TODO: Para a aplicação funcionar é necessário configurar: 10 | - Servidor HTTP (Express) 11 | - Rotas para a API REST (Express/Node Restful) 12 | - Conexão com Banco de Dados (Mongoose/MongoDB). 13 | 14 | # Api 15 | API REST foi implementada utilizando um módulo node chamado [node-restful](https://github.com/baugarten/node-restful). 16 | # Build and Test 17 | 18 | ## Configuração 19 | 1. Instalar os módulos do node utilizando o **npm**. 20 | ```sh 21 | $ npm install 22 | ``` 23 | 24 | 2. Inicializar a aplicação em **modo desenvolvimento**. 25 | ```sh 26 | $ npm run dev 27 | ``` 28 | 29 | 3. Inicializar a aplicação em **modo produção**. 30 | ```sh 31 | $ npm run start 32 | -------------------------------------------------------------------------------- /api/recommendation/recommendation.js: -------------------------------------------------------------------------------- 1 | const { find } = require('lodash') 2 | const beautifyUnique = require('mongoose-beautiful-unique-validation') 3 | const restful = require('node-restful') 4 | const mongoose = restful.mongoose 5 | 6 | const recommendationSchema = new mongoose.Schema({ 7 | fullName: { type: String, required: true }, 8 | description: { type: String, required: false }, 9 | stars: { type: Number, required: false }, 10 | situation: { type: String, required: false }, 11 | status: { type: Boolean, required: true }, 12 | }) 13 | 14 | recommendationSchema.plugin(beautifyUnique) 15 | 16 | module.exports = restful.model('Recommendation', recommendationSchema ) -------------------------------------------------------------------------------- /api/recommendation/recommendationService.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const Recommendation = require('./recommendation') 3 | const fullNameRegex = /^[A-ZÀ-Ÿ][A-zÀ-ÿ']+\s([A-zÀ-ÿ']\s?)*[A-ZÀ-Ÿ][A-zÀ-ÿ']+$/ 4 | 5 | // Gerenciamento da API REST 6 | Recommendation.methods(['get', 'post', 'put', 'delete']) 7 | Recommendation.updateOptions({ new: true, runValidators: true }) 8 | 9 | // Tratativa das mensagens de erro. Retorna apenas o campo com erro - Insert 10 | Recommendation.after('post', sendErrorsOrNext).after('put', sendErrorsOrNext) 11 | Recommendation.before('post', recommendation).before('put', recommendation) 12 | 13 | function sendErrorsOrNext(req, res, next) { 14 | const bundle = res.locals.bundle 15 | 16 | if (bundle.errors) { 17 | var errors = parseErrors(bundle.errors) 18 | res.status(500).json({ errors }) 19 | } else { 20 | next() 21 | } 22 | } 23 | 24 | // Gerencia as mensagens de erros geradas no front-end 25 | function parseErrors(nodeRestfulErrors) { 26 | const errors = [] 27 | _.forIn(nodeRestfulErrors, error => errors.push(error.message)) 28 | return errors 29 | } 30 | 31 | // Serviço para contar a quantidade de registros gerados para a paginação do front-end. 32 | Recommendation.route('count', function (req, res, next) { 33 | Recommendation.count(function (error, value) { 34 | if (error) { 35 | res.status(500).json({ errors: [error] }) 36 | } else { 37 | res.json({ value }) 38 | } 39 | }) 40 | }) 41 | 42 | const sendErrorsFromDB = (res, dbErrors) => { 43 | const errors = [] 44 | _.forIn(dbErrors.errors, error => errors.push(error.message)) 45 | return res.status(400).json({ errors }) 46 | } 47 | 48 | function recommendation(req, res, next){ 49 | const fullName = req.body.fullName || '' 50 | const description = req.body.description || '' 51 | const stars = req.body.stars || '' 52 | const situation = req.body.situation || '' 53 | 54 | if (fullName == null || fullName == "") { 55 | return res.status(400).send({ alert: ["O campos Nome Completo é obrigatório."] }) 56 | } 57 | 58 | if (!fullName.match(fullNameRegex)) { 59 | return res.status(400).send({ alert: ['Informe o nome e sobrenome.'] }) 60 | } 61 | 62 | if (description.length > 500) { 63 | return res.status(400).send({ alert: ["O campo permite apenas 500 caracteres."] }) 64 | } 65 | 66 | if (stars == null || stars == "") { 67 | return res.status(400).send({ alert: ["Informe a quantidade de estrelas que deseja classificar."] }) 68 | } 69 | 70 | const newBody = new Recommendation( 71 | { 72 | fullName: fullName, 73 | description, 74 | situation: "Pendente", 75 | stars, 76 | status: true 77 | }) 78 | newBody.save(err => { 79 | if (err) { 80 | return sendErrorsFromDB(res, err) 81 | } else { 82 | res.status(201).json(newBody) 83 | } 84 | }) 85 | } 86 | 87 | module.exports = Recommendation -------------------------------------------------------------------------------- /api/register/register.js: -------------------------------------------------------------------------------- 1 | const { find } = require('lodash') 2 | const beautifyUnique = require('mongoose-beautiful-unique-validation') 3 | const restful = require('node-restful') 4 | const mongoose = restful.mongoose 5 | 6 | const registerSchema = new mongoose.Schema({ 7 | fullName: { type: String, required: true }, 8 | mail: { type: String, required: true }, 9 | phone: { type: String, required: false }, 10 | address: { type: String, required: true }, 11 | number: { type: Number, required: false }, 12 | complement: { type: String, required: false } 13 | }) 14 | 15 | registerSchema.plugin(beautifyUnique) 16 | 17 | module.exports = restful.model('Register', registerSchema ) -------------------------------------------------------------------------------- /api/register/registerService.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const Register = require('./register') 3 | const fullNameRegex = /^[A-ZÀ-Ÿ][A-zÀ-ÿ']+\s([A-zÀ-ÿ']\s?)*[A-ZÀ-Ÿ][A-zÀ-ÿ']+$/ 4 | const mailRegex = /\S+@\S+\.\S+/; 5 | 6 | Register.methods(['get', 'post', 'put', 'delete']) 7 | Register.updateOptions({ new: true, runValidators: true }) 8 | 9 | Register.after('post', sendErrorsOrNext).after('put', sendErrorsOrNext) 10 | Register.before('post', register).before('put', register) 11 | 12 | function sendErrorsOrNext(req, res, next) { 13 | const bundle = res.locals.bundle 14 | 15 | if (bundle.errors) { 16 | var errors = parseErrors(bundle.errors) 17 | res.status(500).json({ errors }) 18 | } else { 19 | next() 20 | } 21 | } 22 | 23 | function parseErrors(nodeRestfulErrors) { 24 | const errors = [] 25 | _.forIn(nodeRestfulErrors, error => errors.push(error.message)) 26 | return errors 27 | } 28 | 29 | const sendErrorsFromDB = (res, dbErrors) => { 30 | const errors = [] 31 | _.forIn(dbErrors.errors, error => errors.push(error.message)) 32 | return res.status(400).json({ errors }) 33 | } 34 | 35 | function register(req, res, next) { 36 | const fullName = req.body.fullName || '' 37 | const mail = req.body.mail || '' 38 | const phone = req.body.phone || '' 39 | const address = req.body.address || '' 40 | const number = req.body.number || '' 41 | const complement = req.body.complement || '' 42 | 43 | if(!fullName.match(fullNameRegex)){ 44 | return res.status(400).send({ alert: ["Informe o Nome e Sobrenome."]}) 45 | } 46 | 47 | if(mail == null || mail == ""){ 48 | return res.status(400).send({ alert: ["O campo E-mail é obrigatório."]}) 49 | } 50 | 51 | if(!mail.match(mailRegex)){ 52 | return res.status(400).send({ alert: ["O e-mail informado é inválido. Informe um e-mail no formato [nome@dominio.com ou nome@dominio.com.br]."]}) 53 | } 54 | 55 | const newBody = new Register({ 56 | fullName, 57 | mail, 58 | phone, 59 | address, 60 | number, 61 | complement 62 | }) 63 | 64 | newBody.save(err => { 65 | if (err) { 66 | return sendErrorsFromDB(res, err) 67 | } else { 68 | res.status(201).json(newBody) 69 | } 70 | }) 71 | } 72 | 73 | module.exports = Register -------------------------------------------------------------------------------- /config/cors.js: -------------------------------------------------------------------------------- 1 | module.exports = function (req, res, next) { 2 | res.header('Acess-Control-Allow-Origin', '*') 3 | res.header('Acess-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE') 4 | res.header('Acess-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization') 5 | next() 6 | } -------------------------------------------------------------------------------- /config/database.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const args = require("args-parser")(process.argv) 3 | mongoose.Promise = require("bluebird") 4 | 5 | if (args.production) 6 | module.exports = mongoose.connect('mongodb://nome_banco:senha@servidor.com.br:27017/usuario' ) // Umbler 7 | else 8 | mongoose.set('strictQuery', false) 9 | mongoose 10 | .connect( 'mongodb://127.0.0.1:27017/banco_dados', { useNewUrlParser: true, useUnifiedTopology: true }) 11 | .then(() => console.log( 'Database Connected' )) 12 | .catch(err => console.log( err )); 13 | 14 | mongoose.Error.messages.general.required = "O campo '{PATH}' é obrigatório." 15 | mongoose.Error.messages.Number.min = "O '{PATH}' informado é menor que o limite mínimo de '{MIN}'." 16 | mongoose.Error.messages.Number.max = "O '{PATH}' informado é maior que o limite máximo de '{MAX}'." 17 | mongoose.Error.messages.String.enum = "O '{VALUE}' não é válido para o campos '{PATH}'." -------------------------------------------------------------------------------- /config/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | module.exports = function (server) { 4 | const protectedApi = express.Router(); 5 | server.use('/api', protectedApi); 6 | 7 | server.use('/status', (req, res) => 8 | res.send(`BACKEND is runner.`) 9 | ); 10 | 11 | const recommendation = require('../api/recommendation/recommendationService'); 12 | recommendation.register(protectedApi, '/recommendation'); 13 | 14 | const register = require('../api/register/registerService'); 15 | register.register(protectedApi, '/register'); 16 | 17 | server.use(express.static(require('path').join(__dirname, '../public'))); 18 | } -------------------------------------------------------------------------------- /config/server.js: -------------------------------------------------------------------------------- 1 | const port = 3000 2 | const bodyParser = require('body-parser') 3 | const express = require('express') 4 | const server = express() 5 | 6 | const queryParser = require('express-query-int') 7 | const allowCors = require('./cors') 8 | 9 | server.use(bodyParser.json({ limit: '50mb' })); 10 | server.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); 11 | server.use(queryParser()); 12 | server.use(allowCors); 13 | server.use(express.static('public')); 14 | 15 | server.listen(port, function(){ 16 | console.log(`BACKEND is runner on port ${port}.`) 17 | }) 18 | 19 | module.exports = server -------------------------------------------------------------------------------- /loader.js: -------------------------------------------------------------------------------- 1 | const server = require('./config/server') 2 | require('./config/database') 3 | require('./config/routes')(server) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend-api", 3 | "version": "1.0.0", 4 | "description": "Projeto de desenvolvimento de API - T7", 5 | "main": "loader.js", 6 | "scripts": { 7 | "dev": "nodemon", 8 | "production": "pm2 start loader.js --name backend-api-t7" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/Qa-Coders/backend-api-nodejs-t7.git" 13 | }, 14 | "author": "William A. da Silva", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/Qa-Coders/backend-api-nodejs-t7/issues" 18 | }, 19 | "homepage": "https://github.com/Qa-Coders/backend-api-nodejs-t7#readme", 20 | "dependencies": { 21 | "args-parser": "^1.3.0", 22 | "body-parser": "^1.20.1", 23 | "express": "^4.18.2", 24 | "express-query-int": "^3.0.0", 25 | "lodash": "^4.17.21", 26 | "mongoose": "^6.9.0", 27 | "mongoose-beautiful-unique-validation": "^7.1.1", 28 | "mongoose-paginate": "^5.0.3", 29 | "node-restful": "^0.2.6", 30 | "pm2": "^5.2.2" 31 | }, 32 | "devDependencies": { 33 | "nodemon": "^2.0.16" 34 | } 35 | } 36 | --------------------------------------------------------------------------------