forked from linuxacademy/robot-shop
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ae1a16f
Showing
33 changed files
with
1,647 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.*.swp | ||
.DS_Store | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
FROM node:8 | ||
|
||
EXPOSE 8080 | ||
|
||
WORKDIR /opt/server | ||
|
||
COPY package.json /opt/server/ | ||
|
||
RUN npm install | ||
|
||
COPY server.js /opt/server/ | ||
|
||
CMD ["node", "server.js"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "catalogue", | ||
"version": "1.0.0", | ||
"description": "product catalogue REST API", | ||
"main": "server.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "SteveW", | ||
"license": "Apache-2.0", | ||
"dependencies": { | ||
"body-parser": "^1.18.1", | ||
"express": "^4.15.4", | ||
"redis": "^2.8.0", | ||
"request": "^2.83.0", | ||
"instana-nodejs-sensor": "^1.28.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
const instana = require('instana-nodejs-sensor'); | ||
const redis = require('redis'); | ||
const request = require('request'); | ||
const bodyParser = require('body-parser'); | ||
const express = require('express'); | ||
|
||
// init tracing | ||
instana({ | ||
tracing: { | ||
enabled: true | ||
} | ||
}); | ||
|
||
var redisConnected = false; | ||
|
||
const app = express(); | ||
|
||
app.use((req, res, next) => { | ||
res.set('Timing-Allow-Origin', '*'); | ||
res.set('Access-Control-Allow-Origin', '*'); | ||
next(); | ||
}); | ||
|
||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use(bodyParser.json()); | ||
|
||
app.get('/health', (req, res) => { | ||
var stat = { | ||
app: 'OK', | ||
redis: redisConnected | ||
}; | ||
res.json(stat); | ||
}); | ||
|
||
|
||
// get cart with id | ||
app.get('/cart/:id', (req, res) => { | ||
redisClient.get(req.params.id, (err, data) => { | ||
if(err) { | ||
console.log('ERROR', err); | ||
res.status(500).send(err); | ||
} else { | ||
if(data == null) { | ||
res.status(404).send('cart not found'); | ||
} else { | ||
res.set('Content-Type', 'application/json'); | ||
res.send(data); | ||
} | ||
} | ||
}); | ||
}); | ||
|
||
// update/create cart | ||
app.get('/add/:id/:sku/:qty', (req, res) => { | ||
// check quantity | ||
var qty = parseInt(req.params.qty); | ||
if(isNaN(qty)) { | ||
res.status(400).send('quantity must be a number'); | ||
return; | ||
} else if(qty < 1) { | ||
res.status(400).send('negative quantity not allowed'); | ||
return; | ||
} | ||
|
||
// look up product details | ||
getProduct(req.params.sku).then((product) => { | ||
console.log('got product', product); | ||
// is the product in stock? | ||
if(product.instock == 0) { | ||
res.status(404).send('out of stock'); | ||
return; | ||
} | ||
// does the cart already exist? | ||
redisClient.get(req.params.id, (err, data) => { | ||
if(err) { | ||
console.log('ERROR', err); | ||
res.status(500).send(err); | ||
} else { | ||
var cart; | ||
if(data == null) { | ||
// create new cart | ||
cart = { | ||
total: 0, | ||
tax: 0, | ||
items: [] | ||
}; | ||
} else { | ||
cart = JSON.parse(data); | ||
} | ||
console.log('got cart', cart); | ||
// add sku to cart | ||
var item = { | ||
qty: qty, | ||
sku: req.params.sku, | ||
name: product.name, | ||
price: product.price, | ||
subtotal: qty * product.price | ||
}; | ||
var list = mergeList(cart.items, item, qty); | ||
cart.items = list; | ||
cart.total = calcTotal(cart.items); | ||
// work out tax @ 20% | ||
cart.tax = (cart.total - (cart.total / 1.2)).toFixed(2); | ||
|
||
// save the new cart | ||
saveCart(req.params.id, cart); | ||
res.json(cart); | ||
} | ||
}); | ||
}).catch((err) => { | ||
res.status(500).send(err); | ||
}); | ||
}); | ||
|
||
// update quantity - remove item when qty == 0 | ||
app.get('/update/:id/:sku/:qty', (req, res) => { | ||
// check quantity | ||
var qty = parseInt(req.params.qty); | ||
if(isNaN(qty)) { | ||
res.status(400).send('quantity must be a number'); | ||
return; | ||
} | ||
|
||
// get the cart | ||
redisClient.get(req.params.id, (err, data) => { | ||
if(err) { | ||
console.log('ERROR', err); | ||
res.status(500).send(err); | ||
} else { | ||
if(data == null) { | ||
res.status(404).send('cart not found'); | ||
} else { | ||
var cart = JSON.parse(data); | ||
var idx; | ||
var len = cart.items.length; | ||
for(idx = 0; idx < len; idx++) { | ||
if(cart.items[idx].sku == req.params.sku) { | ||
break; | ||
} | ||
} | ||
if(idx == len) { | ||
// not in list | ||
res.status(404).send('not in cart'); | ||
} else { | ||
if(qty == 0) { | ||
cart.items.splice(idx, 1); | ||
} else { | ||
cart.items[idx].qty = qty; | ||
cart.items[idx].subtotal = cart.items[idx].price * qty; | ||
} | ||
cart.total = calcTotal(cart.items); | ||
// work out tax @ 20% | ||
cart.tax = (cart.total - (cart.total / 1.2)).toFixed(2); | ||
saveCart(req.params.id, cart); | ||
res.json(cart); | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
|
||
function mergeList(list, product, qty) { | ||
var inlist = false; | ||
// loop through looking for sku | ||
var idx; | ||
var len = list.length; | ||
for(idx = 0; idx < len; idx++) { | ||
if(list[idx].sku == product.sku) { | ||
inlist = true; | ||
break; | ||
} | ||
} | ||
|
||
if(inlist) { | ||
list[idx].qty += qty; | ||
list[idx].subtotal = list[idx].price * list[idx].qty; | ||
} else { | ||
list.push(product); | ||
} | ||
|
||
return list; | ||
} | ||
|
||
function calcTotal(list) { | ||
var total = 0; | ||
for(var idx = 0, len = list.length; idx < len; idx++) { | ||
total += list[idx].subtotal; | ||
} | ||
|
||
return total; | ||
} | ||
|
||
function getProduct(sku) { | ||
return new Promise((resolve, reject) => { | ||
request('http://catalogue:8080/product/' + sku, (err, res, body) => { | ||
if(err) { | ||
reject(err); | ||
} else if(res.statusCode != 200) { | ||
reject(res.statusCode); | ||
} else { | ||
// return object - body is a string | ||
resolve(JSON.parse(body)); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
function saveCart(id, cart) { | ||
console.log('saving cart', cart); | ||
redisClient.setex(id, 3600, JSON.stringify(cart), (err, data) => { | ||
if(err) { | ||
console.log('saveCart ERROR', err); | ||
} | ||
}); | ||
} | ||
|
||
// connect to Redis | ||
var redisClient = redis.createClient({ | ||
host: 'redis' | ||
}); | ||
|
||
redisClient.on('error', (e) => { | ||
console.log('Redis ERROR', e); | ||
}); | ||
redisClient.on('ready', (r) => { | ||
console.log('Redis READY', r); | ||
redisConnected = true; | ||
}); | ||
|
||
// fire it up! | ||
const port = process.env.CART_SERVER_PORT || '8080'; | ||
app.listen(port, () => { | ||
console.log('Started on port', port); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
FROM node:8 | ||
|
||
EXPOSE 8080 | ||
|
||
WORKDIR /opt/server | ||
|
||
COPY package.json /opt/server/ | ||
|
||
RUN npm install | ||
|
||
COPY server.js /opt/server/ | ||
|
||
CMD ["node", "server.js"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "catalogue", | ||
"version": "1.0.0", | ||
"description": "product catalogue REST API", | ||
"main": "server.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"author": "SteveW", | ||
"license": "Apache-2.0", | ||
"dependencies": { | ||
"body-parser": "^1.18.1", | ||
"express": "^4.15.4", | ||
"mongodb": "^2.2.33", | ||
"instana-nodejs-sensor": "^1.28.0" | ||
} | ||
} |
Oops, something went wrong.