Coder Social home page Coder Social logo

appedidos-backend's Introduction

Appedidos REST API - Backend

O resultado final do (backend + frotend) está disponível em: https://fierce-peak-43734.herokuapp.com/.

Instalação

  1. npm install
  2. cp .env.example .env
  3. npm run dev
  4. Abra http://localhost:3333

Requerimentos

mongodb

Esse projeto usa mongodb, e você pode usar o docker-compose para configurar o que for necessário usando o seguinte comando:

docker-compose up

OBS.: O docker daemon (dockerd) deve estar em execução.

npm

Licença

MIT

Pequeno manual introdutório do NodeJS (RESTfull API's)

[TOC]

Este pequeno manual foi feito com a finalidade de me auxiliar na criação de backends utilizando nodeJS e, ao mesmo tempo, fixar meu aprendizado. Creio que possa servir de auxílio para outros que, como eu, desejam começar a utilizar o ecossistema React (nodeJS, ReactJS, React-Native).

O ambiente de desenvolvimento já deve estar previamente configurado, ou seja, os pacotes nodeJS, reactJS , e Yarn já devem ter sido instalados.

Para o banco de dados, utilzaremos o mongoDB por motivos a serem explicados mais à frente. Instale-o em sua máquina ou utilize o serviço on-line e gratuito deles MongoDB Atlas.

Início: Configurando esqueleto genérico de uma aplicação

  • Crie um diretório chamado backend, entre nele e execute:
$ yarn init -y

Isso irá criar o arquivo package.json

Para adicionar pacotes, execute yarn add nome_do_pacote. Ele irá automaticamente para a lista de dependências do app, em package.json.

Numa aplicação web, um pacote comummento adicionado é o express. Ele cria o servidor web e gerencia as requisições e respostas.

$ yarn add express
  • Crie um diretório src para separar o código fonte dos arquivos gerados automaticamente.

  • Crie um arquivo index.js como arquivo inicial da aplicação e inicie o servidor com o seguinte código:

const express = require('express');

const app = express();

app.get('/', (req, res) => {
    res.write('Hello World.\n');
    res.end();
})

app.listen(3333);

Para iniciar o servidor, basta executar: $ node src/index.js. Uma melhor opção, porém, é instalar uma dependência de desenvolvimento (que só é utilizada durante o desenvolvimento do app) chamada nodemon:

$ yarn add nodemon -D

No arquivo packages.json constará a dependência de desenvolvimento (devDependencies) nodemon e sua versão.

  • Adicione um novo objeto chamado scripts com a variável dev igual a nodemon /src/index.js no arquivo packages.json para cofigurar o nodemon. O arquivo package.json fica da segunte forma:
{
  "name": "backend",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "nodemon src/index.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^1.19.1"
  }
}

Basicamente, o nodemon detecta alterações nos arquivos e reinicia automaticamente o servidor, poupando o trabalho de ficar executando $ node src/index.js sempre que alguma alteração for feita.

  • Inicie o servidor:
$ yarn dev

Para a escalabilidade do app, é interessante lidar com as rotas em um local específico. Crie um arquivo routes.js e adicione o código:

const express = require('express');

const routes = new express.Router();

routes.get('/', (req, res) => {
    res.write('Hello from routes!');
    res.end();
});

module.exports = routes;

O arquivo index.js deverá ser alterado para manter a funcionalidade anterior

const express = require('express');

const app = express();

app.use(require('./routes'));

app.listen(3333);
  • Verifique se está tudo correto atualizando a página http://localhost:3333. Você deverá ver o texto Hello from routes!.

Novamente visando a escalabilidade, é interessante que as rotas sejam gerenciadas (ou controladas) em um outro local. Assim conseguimos separar o direcionamento das rotas (para onde elas vão) e sua lógica (o que elas fazem).

  • Crie um diretório controllers, dentro de src.

  • Crie um arquivo chamado PostController.js dentro de controlers com o seguinte conteúdo:

module.exports = {
    async index(req, res) {
        res.write('Hello from controller!');
        res.end();
    }
}
  • Modifique o arquivo routes.js para agora utilizar o controller:
const express = require('express');

const PostController = require('./controllers/PostController');

const routes = new express.Router();

routes.get('/', PostController.index);

module.exports = routes;

O PostController.js exporta as funções que serão executadas em cada rota definida em routes.js.

Agora podemos começar a desenvolver a aplicação em específico. Para fins de verificação, a estrutura de diretórios deverá estar como a imagem abaixo:

estrutura de diretorios

Desenvolvimento: exemplo de uma aplicação

Descrição da aplicação

O aplicativo que será aqui desenvolvido é um gerenciador de pedidos. Imagine um vendedor autônomo que quer controlar melhor suas vendas e oferecer um melhor serviço aos seus clientes. Ele irá fornecer um endereço web para que os clientes possam fazer pedidos de seus produtos on-line.

Com isso em mente, podemos definir as rotas necessárias ao nosso aplicativo. Elas são referentes às ações que os clients poderão realiar. Duas que imediatamente me vêm à cabeça são:

Ator Ação Rota
Cliente Fazer pedido /addPedido
Autônomo Listar pedidos /listPedidos

Naturalmente, outras ações (e consequentemente rotas) como "Marcar pedido como entregue" ou "Cancelar pedido" podem ser adicionadas posteriormente. Agora vamos nos preocupar com essas duas rotas.

Adicionando rotas

  • Modifique os arquivos PostController.js e routes.js para adicionar um novo pedido no banco de dados quando o caminho (rota) for http://localhost:3333/addPedido.

PostController.js

module.exports = {
    async index(req, res) {
        res.write('Hello from controller!');
        res.end();
    },

    async adicionar(req, res) {
        console.log('Rota: adicionar pedido');
    }
}

routes.js

routes.get('/', PostController.index);
routes.post('/addPedido', PostController.adicionar);

OBS.: Iremos trabalhar com um banco de dados não-relacional, o mongoDB. Não iremos relacionar uma tabela "pedidos" com uma tabela "usuários", iremos apenas adicionar pedidos. Estou assumindo que o autônomo possui os dados de seus clientes (endereço, telefone etc) e que, pra ele, só os pedidos importam. No futuro, podemos colocar um bando de dados relacional (como o MySQL) para gerenciar nossos pedidos.

Ao acessar http://localhost:3333/addPedido, o browser nos retorna algo como Cannot GET /addPedido por dois motivos: (a) não estamos retornando nada para o browser (através de res.write() e res.end()); e (b) estamos fazendo uma requisição do tipo GET, sendo que nosso controller está esperando uma requisição do tipo POST.

Entretanto podemos ver no terminal: Rota: adicionar pedido indicando que nosso código está ok, estamos conseguindo chamar a função adicionar em PostController.js.

Para facilitar o desenvolvimento de nossa API, recomendo a instalação do Insomnia. Ele é capaz de fazer qualquer tipo de requisição e, porcaus disso, nos será muito útil.

Refinando as rotas (definindo a lógica)

Para esse rota específica, a de adicionar um pedido (/addPedido), o usuário irá interagir através de um form HTML. Como estamos desenvolvendo a API, o backend, não iremos criar um arquivo HTML com o código que irá gerar o formulário de pedidos. Para gerar essa requisição, utilizaremos o Insomnia.

No Insomnia, crie uma pasta para gerenciar as requisições de nossa aplicação. Chamei a aplicação de Appedidos =). Dentro da pasta, crie uma nova requisição de nome "Criar pedido" do tipo "POST" e de body "Form URL Encoded". Crie 3 campos de nomes "cliente", "produto" e "entrega" para se referir ao nome do cliente, ao produto a ser pedido e à data de entrega, respectivamente. Coloque o endereço http://localhost:3333/addPedido. Ao final, seu Insomnia deve estar mais ou menos assim:

requisicao

Isso vai "emular" o usuário adicionando um novo pedido pelo frontend, através de um formulário da página ou pelo aplicativo. Para o backend, é só isso que importa.

Vamos utilizar o mongoose para nos comunicarmos com o mongoDB. Devemos então adicioná-lo às nossas dependências do app:

$ yarn add mongoose

Para mantermos nosso código enxuto e, mais uma vez, visando a escalabilidade, vamos criar uma pasta models onde ficarão os esquemas (schemas) de nosso BD. Os esquemas podem ser entendidos como as tabelas do nosso BD.

Dentro do diretório models, crie o arquivo Pedido.js e adicione o código para criar o schema:

const mongoose = require('mongoose');

const PedidoSchema = mongoose.Schema({
    cliente: String,
    produto: String,
    entrega: String,
    isEntregue: Boolean,
});

module.exports = mongoose.model('Pedido', PedidoSchema);

Criamos uma variável to tipo Schema, com os pares campo: tipo do campo. O campo isEntregue define se o pedido foi entregue ou não e será iniciado com false.

Para visualizarmos os dados da requisição do usuário:

1) modifique PostController.js

module.exports = {
    async index(req, res) {
        res.write('Hello from controller!');
        res.end();
    },

    async adicionar(req, res) {
        console.log(req.body);
        return res.json(req.body);
    }
}

2) Adicione app.use(express.urlencoded()); ao arquivo index.js para reconhecer requisições de formulários:

const express = require('express');
const mongoose = require('mongoose');

const app = express();

mongoose.connect('mongodb://localhost:27017/mongoDB', {
    useNewUrlParser: true,
});

app.use(express.urlencoded());
app.use(require('./routes'));

app.listen(3333);

3) Envie a requisição através do Insomnia, apertando Send.

O resultado será algo como: resposta

Você também poderá ver no temrinal: { cliente: 'Andre', produto: 'produto 1', entrega: '23/06/2019' }

Adicionando ao Banco de Dados Mongo

A partir de agora, os códigos-fonte dos arquivos não serão exibidos por completo, mas sim só o código a ser adicionado/alterado juntamente com parte do código para facilitar a localização. As reticências (...) no fim ou começo do bloco de código indicam que há mais código além delas.

Uma vez instalado o mongoDB (ou utilizando o serviço MongoDB Atlas), é preciso informar a aplicação a localização do bancode dados. Para isso adicione ao index.js:

...
const app = express();

mongoose.connect('mongodb://localhost:27017/mongoDB', {
    useNewUrlParser: true,
});

app.use(express.urlencoded());
...

Caso tenha escolhido insalar o mongoDB na sua máquina, crie uma pasta mongoDB dentro de backend e, uma pasta data dentro de mongoDB e inicie o mongoDB, dentro do diretório backend, com o comando:

$ mongod -dbpath mongoDB/

Assim, o caminho mostrado no bloco de código acima funcionará pra você.

Modifique o arquivo PostController.js de forma que a função adicionar fique da seguinte forma:

...
async adicionar(req, res) {
    const {
        cliente,
        produto,
        entrega,
    } = req.body;
    const isEntregue = false;

    const registro = await Pedido.create({
        cliente,
        produto,
        entrega,
        isEntregue,
    });

    return res.json(registro);
},
...

No primeiro 'bloco', são criadas variáveis para armazenar o conteúdo do form. É criada uma variável para armazenar que o pedido ainda não foi entregue. O segundo bloco é o armazenamento no MongoDB em si, através da função create. Lembre-se que Pedido é um schema do mongo, definido em models/Pedido.js. O resultado do armazenamento, chamado de registro, é o que retorna da função. É o que nossa API vai devolver ao frontend.

Podemos ver, através do Insomnia, que o pedido foi armazenado no banco de dados quando ele retorna um _id, campo criado automaticamente pelo mongo.

armazenamento

Concluímos a definição de nossa primeira rota. O usuário já pode fazer um pedido ao nosso vendedor autônomo. A aplicação irá armazenar esse pedido que contém o nome do cliente, o produto desejado e a data desejável da entrega. O pedido tem também um campo que não é mostrado ao usuário, que diz se o pedido já foi entregue ou não. Somente o vendedor que poderá visualizar esse campo e alterá-lo.

Listando os pedidos

Chegou a hora de começarmos a definir uma nova rota: a de listagem de pedidos: /listPedidos.

Adicione a nova rota em routes.js:

...
routes.post('/addPedido', PostController.adicionar);

routes.get('/listPedidos', PostController.listar);
...

A função no nosso controller foi chamada de listar. Devemos criá-la, então, em PostController.js:

...
async listar(req, res) {
    const pedidos = await Pedido.find();

    return res.json(pedidos);
},

Não esqueça de adicionar uma vírgula (,) após a chave de fechamento da função anterior.

Lembre-se, novamente, que Pedidos é um objeto schema do mongo, cotendo métodos e propriedades. Utilizamos o método find() para listar todos os registros. Poderíamos colocar filtros como nome do cliente, mas no nosso caso a listagem é completa, sem filtros.

Para testar a rota /listPedidos podemos utilizar o próprio navegador, já que é uma rota do tipo GET, acessando http://localhost:3333/listPedidos. Porém, vamos utilizar o Insomnia criando uma nova requisição GET de nome Listar pedidos. Após digitar o endereço http://localhost:3333/listPedidos e pressionar Send, um resultado como o seguinte deve aparecer:

listagem

Pronto! Concluímos as duas rotas que definimos no início do desenvolvimento da aplicação. Vários recursos foram vistos neste exercício e há muito espaço para melhoramentos. Um mais urgente é adicionar uma nova rota para que o vendedor possa marcar um pedido como entregue e ele suma da lista de pedidos. Outro seria a possibilidade de visualizar os pedidos já entregues, ordenar por cliente, etc.

Caso algo sobre a estrutura dos diretórios não tenha ficado muito claro, assim deverá ficar a estrutura final:

estrutura

O próximo manual será sobre desenvolver um frontend utilizando ReactJS.

appedidos-backend's People

Contributors

amelco avatar davidcostadev avatar

Watchers

 avatar  avatar

Forkers

davidcostadev

appedidos-backend's Issues

Implement Best Practice on REST Routes

routes.get('/', PostController.index);
routes.post('/addPedido', PostController.adicionar);
routes.get('/listPedidos', PostController.listar);
routes.post('/listPedidos/:id/entregar', PostController.entregar);
routes.post('/listPedidos/:id/deletar', PostController.deletar);

It's recommended use the RESTFUL way to create endpoints.

For example, if you have a model 'pedidos', your endpoints should be like:

  • GET /pedidos to get all list of 'pedidos';
  • POST /pedidos to create a new 'pedidos';
  • GET /pedidos/:id to get only one 'pedido';
  • PUT /pedidos/:id to edit the 'pedido';
  • DELETE /pedidos/id to delete the 'pedido';

And the express.Router should be some like:

routes.get('/pedidos', PostController.listar);
routes.post('/pedidos', PostController.adicionar);
routes.get('/pedidos/:id', PostController.get); 
routes.put('/pedidos/:id', PostController.editar);
routes.delete('/pedidos/:id', PostController.deletar);

On frontend using the lib axios you can use it like:

await axios.get('/pedidos');
await axios.get('/pedidos?isEntregue=true');
await axios.post('/pedidos', data);
await axios.put(`/pedidos/${id}`,{ isEntregue: true });
await axios.delete(`/pedidos/${id}`);

For the name of endpoint is recommend use the same name of the table on your database, and if the is composite terms for example pedidos_produtos the and name should be converted to came case. Ex.: /pedidosProdutos.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.