├── cypress ├── cypress.json ├── cypress │ └── integration │ │ └── spec1.js └── Dockerfile ├── services ├── frontend │ ├── img │ │ ├── esm.png │ │ ├── design.png │ │ └── refactoring.png │ ├── index.css │ ├── index.html │ └── index.js ├── controller │ ├── shipping.js │ ├── inventory.js │ └── index.js ├── inventory │ ├── products.json │ └── index.js └── shipping │ └── index.js ├── proto ├── shipping.proto └── inventory.proto ├── LICENSE ├── package.json └── README.md /cypress/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fixturesFolder": false, 3 | "pluginsFile": false, 4 | "supportFile": false 5 | } -------------------------------------------------------------------------------- /services/frontend/img/esm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aserg-ufmg/demo-cypress/HEAD/services/frontend/img/esm.png -------------------------------------------------------------------------------- /services/frontend/img/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aserg-ufmg/demo-cypress/HEAD/services/frontend/img/design.png -------------------------------------------------------------------------------- /services/frontend/img/refactoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aserg-ufmg/demo-cypress/HEAD/services/frontend/img/refactoring.png -------------------------------------------------------------------------------- /cypress/cypress/integration/spec1.js: -------------------------------------------------------------------------------- 1 | describe('Meu primeiro teste', () => { 2 | it('Não faz nada', () => { 3 | expect(true).to.equal(true) 4 | }) 5 | }) 6 | -------------------------------------------------------------------------------- /cypress/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node 2 | 3 | ENV NO_UPDATE_NOTIFIER=1 4 | 5 | EXPOSE 3000 6 | EXPOSE 5000 7 | 8 | WORKDIR /app 9 | 10 | ADD . . 11 | RUN npm install --silent --loglevel=error 12 | 13 | CMD ["npm", "run", "exec"] 14 | -------------------------------------------------------------------------------- /proto/shipping.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service ShippingService { 4 | rpc GetShippingRate(ShippingPayload) returns (ShippingResponse) {} 5 | } 6 | 7 | message ShippingPayload { 8 | string cep = 1; 9 | } 10 | 11 | message ShippingResponse { 12 | float value = 1; 13 | } 14 | -------------------------------------------------------------------------------- /proto/inventory.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | service InventoryService { 4 | rpc SearchAllProducts(Empty) returns (ProductsResponse) {} 5 | } 6 | 7 | message Empty{} 8 | 9 | message ProductResponse { 10 | int32 id = 1; 11 | string name = 2; 12 | int32 quantity = 3; 13 | float price = 4; 14 | string photo = 5; 15 | string author = 6; 16 | } 17 | 18 | message ProductsResponse { 19 | repeated ProductResponse products = 1; 20 | } 21 | -------------------------------------------------------------------------------- /services/controller/shipping.js: -------------------------------------------------------------------------------- 1 | const grpc = require('@grpc/grpc-js'); 2 | const protoLoader = require('@grpc/proto-loader'); 3 | 4 | const packageDefinition = protoLoader.loadSync('proto/shipping.proto', { 5 | keepCase: true, 6 | longs: String, 7 | enums: String, 8 | arrays: true, 9 | }); 10 | 11 | const ShippingService = grpc.loadPackageDefinition(packageDefinition).ShippingService; 12 | const client = new ShippingService('127.0.0.1:3001', grpc.credentials.createInsecure()); 13 | 14 | module.exports = client; 15 | -------------------------------------------------------------------------------- /services/controller/inventory.js: -------------------------------------------------------------------------------- 1 | const grpc = require('@grpc/grpc-js'); 2 | const protoLoader = require('@grpc/proto-loader'); 3 | 4 | const packageDefinition = protoLoader.loadSync('proto/inventory.proto', { 5 | keepCase: true, 6 | longs: String, 7 | enums: String, 8 | arrays: true, 9 | }); 10 | 11 | const InventoryService = grpc.loadPackageDefinition(packageDefinition).InventoryService; 12 | const client = new InventoryService('127.0.0.1:3002', grpc.credentials.createInsecure()); 13 | 14 | module.exports = client; 15 | -------------------------------------------------------------------------------- /services/inventory/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Refactoring", 5 | "author": "Martin Fowler", 6 | "quantity": 10, 7 | "price": 79.92, 8 | "photo": "/img/refactoring.png" 9 | }, 10 | { 11 | "id": 2, 12 | "name": "Engenharia De Software Moderna", 13 | "author": "Marco Tulio Valente", 14 | "quantity": 10, 15 | "price": 65.9, 16 | "photo": "/img/esm.png" 17 | }, 18 | { 19 | "id": 3, 20 | "name": "Design Patterns", 21 | "author": "Erich Gamma, John Vlissides, Richard Helm, Ralph Johnson", 22 | "quantity": 10, 23 | "price": 67.99, 24 | "photo": "/img/design.png" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /services/inventory/index.js: -------------------------------------------------------------------------------- 1 | const grpc = require('@grpc/grpc-js'); 2 | const protoLoader = require('@grpc/proto-loader'); 3 | const products = require('./products.json'); 4 | 5 | const packageDefinition = protoLoader.loadSync('proto/inventory.proto', { 6 | keepCase: true, 7 | longs: String, 8 | enums: String, 9 | arrays: true, 10 | }); 11 | 12 | const inventoryProto = grpc.loadPackageDefinition(packageDefinition); 13 | 14 | const server = new grpc.Server(); 15 | 16 | // implementa os métodos do InventoryService 17 | server.addService(inventoryProto.InventoryService.service, { 18 | searchAllProducts: (_, callback) => { 19 | callback(null, { 20 | products: products, 21 | }); 22 | }, 23 | }); 24 | 25 | server.bindAsync('127.0.0.1:3002', grpc.ServerCredentials.createInsecure(), () => { 26 | console.log('Inventory Service running at http://127.0.0.1:3002'); 27 | server.start(); 28 | }); 29 | -------------------------------------------------------------------------------- /services/shipping/index.js: -------------------------------------------------------------------------------- 1 | const grpc = require('@grpc/grpc-js'); 2 | const protoLoader = require('@grpc/proto-loader'); 3 | 4 | const packageDefinition = protoLoader.loadSync('proto/shipping.proto', { 5 | keepCase: true, 6 | longs: String, 7 | enums: String, 8 | arrays: true, 9 | }); 10 | 11 | const shippingProto = grpc.loadPackageDefinition(packageDefinition); 12 | 13 | const server = new grpc.Server(); 14 | 15 | // implementa os métodos do ShippingService 16 | server.addService(shippingProto.ShippingService.service, { 17 | GetShippingRate: (_, callback) => { 18 | const shippingValue = Math.random() * 100 + 1; // Random value from R$1 to R$100 19 | 20 | callback(null, { 21 | value: shippingValue, 22 | }); 23 | }, 24 | }); 25 | 26 | server.bindAsync('0.0.0.0:3001', grpc.ServerCredentials.createInsecure(), () => { 27 | console.log('Shipping Service running at http://127.0.0.1:3001'); 28 | server.start(); 29 | }); 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Applied Software Engineering Research Group 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /services/controller/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const shipping = require('./shipping'); 3 | const inventory = require('./inventory'); 4 | const cors = require('cors'); 5 | 6 | const app = express(); 7 | app.use(cors()); 8 | 9 | /** 10 | * Retorna a lista de produtos da loja via InventoryService 11 | */ 12 | app.get('/products', (req, res, next) => { 13 | inventory.SearchAllProducts(null, (err, data) => { 14 | if (err) { 15 | console.error(err); 16 | res.status(500).send({ error: 'something failed :(' }); 17 | } else { 18 | res.json(data.products); 19 | } 20 | }); 21 | }); 22 | 23 | /** 24 | * Consulta o frete de envio no ShippingService 25 | */ 26 | app.get('/shipping/:cep', (req, res, next) => { 27 | shipping.GetShippingRate( 28 | { 29 | cep: req.params.cep, 30 | }, 31 | (err, data) => { 32 | if (err) { 33 | console.error(err); 34 | res.status(500).send({ error: 'something failed :(' }); 35 | } else { 36 | res.json({ 37 | cep: req.params.cep, 38 | value: data.value, 39 | }); 40 | } 41 | } 42 | ); 43 | }); 44 | 45 | /** 46 | * Inicia o router 47 | */ 48 | app.listen(3000, () => { 49 | console.log('Controller Service running on http://127.0.0.1:3000'); 50 | }); 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "micro-livraria", 3 | "version": "1.0.0", 4 | "description": "Toy example of microservice", 5 | "main": "", 6 | "scripts": { 7 | "start": "run-p start-frontend start-controller start-shipping start-inventory", 8 | "start-controller": "nodemon services/controller/index.js", 9 | "start-shipping": "nodemon services/shipping/index.js", 10 | "start-inventory": "nodemon services/inventory/index.js", 11 | "start-frontend": "serve services/frontend", 12 | "exec": "run-p start-frontend exec-controller exec-shipping exec-inventory", 13 | "exec-controller": "node services/controller/index.js", 14 | "exec-shipping": "node services/shipping/index.js", 15 | "exec-inventory": "node services/inventory/index.js" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/aserg-ufmg/micro-livraria.git" 20 | }, 21 | "author": "Rodrigo", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/aserg-ufmg/micro-livraria/issues" 25 | }, 26 | "homepage": "https://github.com/aserg-ufmg/micro-livraria#readme", 27 | "dependencies": { 28 | "@grpc/grpc-js": "^1.2.6", 29 | "@grpc/proto-loader": "^0.5.6", 30 | "cors": "^2.8.5", 31 | "express": "^4.17.1", 32 | "google-protobuf": "^3.15.0-rc.1" 33 | }, 34 | "devDependencies": { 35 | "serve": "^12.0.0", 36 | "nodemon": "^2.0.7", 37 | "npm-run-all": "^4.1.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /services/frontend/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | background: #eff3f4; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', 5 | sans-serif; 6 | } 7 | 8 | .hero-body .container { 9 | max-width: 700px; 10 | } 11 | 12 | .hero-body .title { 13 | color: hsl(192, 17%, 99%) !important; 14 | } 15 | 16 | .hero-body .subtitle { 17 | color: hsl(192, 17%, 99%) !important; 18 | padding-top: 2rem; 19 | line-height: 1.5; 20 | } 21 | 22 | .features { 23 | padding: 5rem 0; 24 | } 25 | 26 | .box.cta { 27 | border-radius: 0; 28 | border-left: none; 29 | border-right: none; 30 | } 31 | 32 | .card-image > .fa { 33 | font-size: 8rem; 34 | padding-top: 2rem; 35 | padding-bottom: 2rem; 36 | color: #209cee; 37 | } 38 | 39 | .card-content .content { 40 | font-size: 14px; 41 | margin: 1rem 1rem; 42 | } 43 | 44 | .card-content .content h4 { 45 | font-size: 16px; 46 | font-weight: 700; 47 | } 48 | 49 | .card { 50 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.18); 51 | margin-bottom: 2rem; 52 | } 53 | 54 | .is-shady { 55 | animation: flyintoright 0.4s backwards; 56 | background: #fff; 57 | box-shadow: rgba(0, 0, 0, 0.1) 0 1px 0; 58 | border-radius: 4px; 59 | display: inline-block; 60 | margin: 10px; 61 | position: relative; 62 | transition: all 0.2s ease-in-out; 63 | width: 100%; 64 | } 65 | 66 | .is-shady:hover { 67 | box-shadow: 0 10px 16px rgba(0, 0, 0, 0.13), 0 6px 6px rgba(0, 0, 0, 0.19); 68 | } 69 | 70 | @media (min-width: 800px) { 71 | .book-meta { 72 | min-height: 250px; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /services/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |Micro Livraria
18 |Uma simples livraria utilizando microservices
23 |