AWS NodeJS App 06 – Carrinho de compras com Time To Live do DynamoDB – Parte 1
O objetivo deste tutorial é implementar a funcionalidade de carrinho de compras, para isso vamos armazenar temporariamente objetos em nosso DynamoDB. E para isso vamos utilizar no ID da sessão HTTP como chave para identificar nossos usuários. Para isso precisamos instalar duas bibliotecas em nosso projeto.
npm install express-session --save
npm install cookie-parser --save
Para que estas bibliotecas funcionem precisamos modificar nosso arquivo app.js para importar e coloca-las no pipeline de processamento do express.


//muito código antes disso var cookieParser = require('cookie-parser'); var session = require('express-session'); //mais código ainda app.use(cookieParser()); app.use(session({ secret: 'wV95QY67vRxWtDOQJO0194NUJdl5zYam', // just a long random string resave: false, saveUninitialized: true }));
Em seguida na pasta models vamos criar uma nova classe chamada ShoppingCar para representar o carrinho de compras.

var { DataMapper, DynamoDbSchema, DynamoDbTable } = require('@aws/dynamodb-data-mapper'); class ShoppingCar{ } Object.defineProperties(ShoppingCar.prototype, { [DynamoDbTable]: { value: 'shoppingcar' }, [DynamoDbSchema]: { value: { id: { type: 'String', keyType: 'HASH' }, expiration: {type: 'Number'}, itens: { type: 'Collection' } }, }, }); module.exports = ShoppingCar;
Agora vamos ao DynamoDB criar nossa nova tabela chamada shoppingcar, e vamos definir a propriedade expiration como nos Time to live attribute. Assim os documentos desta tabela serão automaticamente excluídos após um período de tempo.

Para saber mais sobre o TTL veja este site: https://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/howitworks-ttl.html
Em seguida vamos retornar ao nosso projeto e criar uma nova classe de serviço chamada ShoppingCarService, nesta classe vamos implementar dois métodos um para salvar um novo carrinho de compras e outro para recuperar o carrinho de compras pela propriedade id.

var { DataMapper, DynamoDbSchema, DynamoDbTable } = require('@aws/dynamodb-data-mapper'); var ConditionExpression = require('@aws/dynamodb-expressions'); var {contains} = require('@aws/dynamodb-expressions'); var DynamoDB = require('aws-sdk/clients/dynamodb'); const client = new DynamoDB({region: 'us-east-2'}); const mapper = new DataMapper({client}); const Product = require("../models/product"); const ShoppingCar = require("../models/shoppingcar"); class ShoppingCarService{ async save(shoppingCar){ if(shoppingCar.id == null || shoppingCar.id === ""){ throw Error("Todo carrinho de compras deve ter um ID"); } mapper.put({item: shoppingCar}).then(() => { return shoppingCar; }); } async getById(idshoppingcar){ var resultado = mapper.get(Object.assign(new ShoppingCar(), {id: idshoppingcar})) .catch(err => { return null; }); return resultado; } } module.exports = ShoppingCarService;
Podemos agora modificar nossa view index2.hbs do controlador index para que o botão Buy now chame o novo controlador shoppingcar na action add product passando o ID do produto selecionado.

<a href="/shoppingcar/addproduct?productid={{this.id}}" class="btn btn-primary"> Buy now </a>
O próximo passo será criar o ShoppingCarController, nesta classe vamos criar o código da action addProduct que irá recuperar o id do produto selecionado, o identificador único da sessão. Em seguida nosso código chama a classe de serviço para verificar se encontra no DynamoDB algum objeto com o id igual ao id da sessão do usuário, caso não encontre ele cria um novo objeto contendo o id da sessão, o valor de expiração do documento e uma array de itens. Em seguida ele insere um novo objeto na lista de itens contendo o ID do produto selecionado e a quantidade inicial de 1 item.

var ProductService = require("../services/productservice"); var productService = new ProductService(); var Product = require("../models/product"); var ShoppingCarService = require("../services/shoppingcarservice"); var shoppingCarService = new ShoppingCarService(); var ShoppingCar = require("../models/shoppingcar"); class ShoppingCarController{ async addProduct(req,res,next){ var idproduct = req.query.productid; var sessionid = req.sessionID; await shoppingCarService.getById(sessionid).then((shoppingcar)=>{ if(shoppingcar == null){ shoppingcar = new ShoppingCar(); shoppingcar.id = sessionid; shoppingcar.expiration = Math.floor( Date.now() / 1000 ) + 60; shoppingcar.itens = new Array(); } //console.log(JSON.stringify(shoppingcar, null, 10)); shoppingcar.itens.push({id:idproduct,quantity:1}); shoppingCarService.save(shoppingcar); }); res.redirect("/"); } } module.exports = ShoppingCarController;
Agora nos devemos registrar nosso controlador, para isso vamos criar um novo arquivo na pasta de routes chamado shoppingcar.js criando a rota /addproduct.

var express = require('express'); var router = express.Router(); var ShoppingCarController = require("../controller/shoppingcarcontroller"); var shoppingCarController = new ShoppingCarController(); router.get('/addproduct', function(req, res, next) { shoppingCarController.addProduct(req,res,next); }); module.exports = router;
E agora vamos novamente alterar nosso arquivo app.js para incluir nosso novo arquivo de rotas para o carrinho de compras.


//muito código antes disso var shoppingcarRouter = require('./routes/shoppingcar'); //várias e várias linhas de código app.use('/shoppingcar', shoppingcarRouter);
Agora execute a aplicação e clique no botão Buy now, em qualquer um dos produtos. Ao acessar o DynamoDB observe que um novo documento será inserido, contendo como chave o id da sessão do usuário e o id do produto.

Por fim podemos alterar nossa tela inicial para apresentar o número de itens que estão no carrinho de compras. Para isso vamos modificar o código do nosso IndexController para incluir o código necessário para carregar o serviço do carrinho de compras, e na action index recuperar o carrinho de compras do usuário e calcular o número de itens que ele já adicionou e então enviar essa informação para a view.

var ShoppingCarService = require("../services/shoppingcarservice"); var shoppingCarService = new ShoppingCarService(); var ShoppingCar = require("../models/shoppingcar"); class IndexController{ async index(req,res,next){ var listProduct = await productService.getAll(); var numitens = 0; await shoppingCarService.getById(req.sessionID).then((shoppingcar)=>{ if(shoppingcar != null) numitens = shoppingcar.itens.length; }); //console.log(JSON.stringify(listProduct, null, 4)); res.render('index/index2', { listProduct: listProduct, numitensshoppingcar:numitens }); }
Para que o número de itens seja apresentado em tela, vamos substituir a informação do telefone de contato no header da tela pelo número de itens que está no carrinho de compras.

<div class="text-wrap"> Carrinho de compras {{numitensshoppingcar}} itens </div>
Agora ao acessar a aplicação o número de itens no carrinho de compras será apresentado no topo da tela. Aguarde alguns minutos e ao atualizar a tela, o carrinho de compras aparecerá zerado pois o documento foi removido automaticamente pelo DynamoDB.
