Skip to content
Permalink
Browse files
added base code for tests
  • Loading branch information
aa7401 committed Sep 13, 2019
1 parent 922bb3d commit 433c90515974e5642ac6d3a0de019043c143d0b5
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 94 deletions.
@@ -1,90 +1,54 @@
#!/usr/bin/env node
/* eslint no-magic-numbers: 0 */

'use strict'

/* import the 'restify' module and create an instance. */
const restify = require('restify')
const server = restify.createServer()

/* import the required plugins to parse the body and auth header. */
server.use(restify.fullResponse())
server.use(restify.bodyParser())
server.use(restify.authorizationParser())

/* import our custom module. */
const lists = require('./lists.js')

/* if we receive a GET request for the base URL redirect to /lists */
server.get('/', (req, res, next) => {
res.redirect('/lists', next)
})

/* this route provides a URL for the 'lists' collection. It demonstrates how a single resource/collection can have multiple representations. */
server.get('/lists', (req, res) => {
console.log('getting a list of all the lists')
/* we will be including URLs to link to other routes so we need the name of the host. Notice also that we are using an 'immutable variable' (constant) to store the host string since the value won't change once assigned. The 'const' keyword is new to ECMA6 and is supported in NodeJS. */
const host = req.headers.host
console.log(host)
/* creating some empty variables */
let data //type
/* is the client requesting xml data? The req.header object stores any headers passed in the request. The 'Accept' header lets the client express a preference for the format of the representation. Note you should always provide a sensible default. */
if (req.header('Accept') === 'application/xml') {
data = lists.getAllXML(host)
} else {
data = lists.getAll(host)
const Koa = require('koa')
const Router = require('koa-router')
const stat = require('koa-static')
const bodyParser = require('koa-bodyparser')
const handlebars = require('koa-hbs-renderer')

const app = new Koa()
const router = new Router()
app.use(stat('public'))
app.use(bodyParser())
app.use(handlebars({ paths: { views: `${__dirname}/views` } }))
app.use(router.routes())

const port = 8080

const todo = require('./modules/todo')

router.get('/', async ctx => {
try {
const data = todo.getAll()
ctx.render('home', {items: data})
} catch(err) {
console.log(err.message)
ctx.render('empty')
}
/* we need to set the content-type to match the data we are sending. We then send the response code and body. Finally we signal the end of the response. */
res.setHeader('content-type', data.contentType)
res.send(data.code, data.response)
res.end()
})

/* This route provides a URL for each list resource. It includes a parameter (indicated by a :). The string entered here is stored in the req.params object and can be used by the script. */
server.get('/lists/:listID', (req, res) => {
console.log('getting a list based on its ID')
/* Here we store the id we want to retrieve in an 'immutable variable'. */
const listID = req.params.listID
/* Notice that all the business logic is kept in the 'lists' module. This stops the route file from becoming cluttered and allows us to implement 'unit testing' (we cover this in a later topic) */
const data = lists.getByID(listID)
res.setHeader('content-type', 'application/json')
res.send(data.code, data.response)
res.end()
})

/* This route points to the 'lists' collection. The POST method indicates that we indend to add a new resource to the collection. Any resource added to a collection using POST should be assigned a unique id by the server. This id should be returned in the response body. */
server.post('/lists', (req, res) => {
console.log('adding a new list')
/* The req object contains all the data associated with the request received from the client. The 'body' property contains the request body as a string. */
const body = req.body
/* Since we are using the authorization parser plugin we gain an additional object which contains the information from the 'Authorization' header extracted into useful information. Here we are displaying it in the console so you can understand its structure. */
const auth = req.authorization
console.log(auth)
const data = lists.addNew(auth, body)
res.setHeader('content-type', data.contentType)
res.send(data.code, data.response)
res.end()
})

/* The PUT method is used to 'update' a named resource. This is not only used to update a named resource that already exists but is also used to create a NEW RESOURCE at the named URL. It's important that you understand how this differs from a POST request. */
server.put('/lists/:listID', (req, res) => {
res.setHeader('content-type', 'application/json')
//res.send(data.code, {status: data.status, message: 'this should update the specified resource'})
res.end()
})

/* The DELETE method removes the resource at the specified URL. */
server.del('/lists/:listID', (req, res) => {
res.setHeader('content-type', 'application/json')
//res.send(data.code, {status: data.status, message: 'this should delete the specified resource'})
res.end()
router.post('/', ctx => {
try {
const body = ctx.request.body
todo.add(body.item, body.qty)
} catch(err) {
console.log(err.message)
} finally {
ctx.redirect('/')
}
})

const port = process.env.PORT || 8080
server.listen(port, err => {
if (err) {
console.error(err)
} else {
console.log('App is ready at : ' + port)
router.get('/delete/:key', ctx => {
try {
console.log(`key: ${ctx.params.key}`)
todo.delete(ctx.params.key)
} catch(err) {
console.log(err.message)
} finally {
ctx.redirect('/')
}
})

module.exports = app.listen(port, () => console.log(`listening on port ${port}`))
@@ -0,0 +1,23 @@

'use strict'

let data = []

module.exports.clear = () => {
data = []
}

module.exports.add = (item, qty) => {
data.push({item: item, qty: qty})
}

module.exports.getAll = () => {
if(data.length === 0) throw new Error('empty list')
for(const key in data) data[key].key = key
return data
}

module.exports.delete = key => {
console.log(`delete key ${key}`)
return
}
@@ -1,25 +1,21 @@
{
"name": "todo",
"version": "1.0.0",
"description": "Simple API to maintain to do lists.",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"api",
"restify",
"tutorial"
],
"author": "Mark J Tyers",
"author": "",
"license": "ISC",
"dependencies": {
"csprng": "^0.1.1",
"restify": "^4.0.3",
"xmlbuilder": "^3.1.0"
},
"devDependencies": {
"frisby": "^0.8.5",
"jasmine-node": "^1.14.5"
"handlebars": "^4.2.0",
"koa": "^2.8.1",
"koa-bodyparser": "^4.2.1",
"koa-handlebars": "^1.0.0",
"koa-hbs-renderer": "^1.2.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"koa-views": "^6.2.1"
}
}
@@ -0,0 +1,11 @@

body {
font-family: Arial, Helvetica, sans-serif;
}

.msg {
border: 1px solid red;
font-weight: bold;
color: red;
padding: 1em;
}
@@ -0,0 +1,19 @@

<!DOCTYPE html>
<html>
<head>
<title>ToDo List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>ToDo List</h1>
<h2>Your list is empty, lets add some items...</h2>
<form method="post" action="/">
Item:
<input type="text" name="item" />
Qty:
<input type="text" name="qty" />
<input type="submit" value="Add Item" />
</form>
</body>
</html>
@@ -0,0 +1,26 @@

<!DOCTYPE html>
<html>
<head>
<title>ToDo List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>ToDo List</h1>
<h2>My List</h2>
<table>
<caption>Shopping List</caption>
<tr><th>Item</th><th>Qty</th><th>Action</th></tr>
{{#each items}}
<tr><td>{{this.item}}</td><td>{{this.qty}}</td><td><a href="/delete/{{this.key}}">delete</a></td></tr>
{{/each}}
</table>
<form method="post" action="/">
Item:
<input type="text" name="item" />
Qty:
<input type="text" name="qty" />
<input type="submit" value="Add Item" />
</form>
</body>
</html>
Empty file.
@@ -0,0 +1,90 @@
#!/usr/bin/env node
/* eslint no-magic-numbers: 0 */

'use strict'

/* import the 'restify' module and create an instance. */
const restify = require('restify')
const server = restify.createServer()

/* import the required plugins to parse the body and auth header. */
server.use(restify.fullResponse())
server.use(restify.bodyParser())
server.use(restify.authorizationParser())

/* import our custom module. */
const lists = require('./lists.js')

/* if we receive a GET request for the base URL redirect to /lists */
server.get('/', (req, res, next) => {
res.redirect('/lists', next)
})

/* this route provides a URL for the 'lists' collection. It demonstrates how a single resource/collection can have multiple representations. */
server.get('/lists', (req, res) => {
console.log('getting a list of all the lists')
/* we will be including URLs to link to other routes so we need the name of the host. Notice also that we are using an 'immutable variable' (constant) to store the host string since the value won't change once assigned. The 'const' keyword is new to ECMA6 and is supported in NodeJS. */
const host = req.headers.host
console.log(host)
/* creating some empty variables */
let data //type
/* is the client requesting xml data? The req.header object stores any headers passed in the request. The 'Accept' header lets the client express a preference for the format of the representation. Note you should always provide a sensible default. */
if (req.header('Accept') === 'application/xml') {
data = lists.getAllXML(host)
} else {
data = lists.getAll(host)
}
/* we need to set the content-type to match the data we are sending. We then send the response code and body. Finally we signal the end of the response. */
res.setHeader('content-type', data.contentType)
res.send(data.code, data.response)
res.end()
})

/* This route provides a URL for each list resource. It includes a parameter (indicated by a :). The string entered here is stored in the req.params object and can be used by the script. */
server.get('/lists/:listID', (req, res) => {
console.log('getting a list based on its ID')
/* Here we store the id we want to retrieve in an 'immutable variable'. */
const listID = req.params.listID
/* Notice that all the business logic is kept in the 'lists' module. This stops the route file from becoming cluttered and allows us to implement 'unit testing' (we cover this in a later topic) */
const data = lists.getByID(listID)
res.setHeader('content-type', 'application/json')
res.send(data.code, data.response)
res.end()
})

/* This route points to the 'lists' collection. The POST method indicates that we indend to add a new resource to the collection. Any resource added to a collection using POST should be assigned a unique id by the server. This id should be returned in the response body. */
server.post('/lists', (req, res) => {
console.log('adding a new list')
/* The req object contains all the data associated with the request received from the client. The 'body' property contains the request body as a string. */
const body = req.body
/* Since we are using the authorization parser plugin we gain an additional object which contains the information from the 'Authorization' header extracted into useful information. Here we are displaying it in the console so you can understand its structure. */
const auth = req.authorization
console.log(auth)
const data = lists.addNew(auth, body)
res.setHeader('content-type', data.contentType)
res.send(data.code, data.response)
res.end()
})

/* The PUT method is used to 'update' a named resource. This is not only used to update a named resource that already exists but is also used to create a NEW RESOURCE at the named URL. It's important that you understand how this differs from a POST request. */
server.put('/lists/:listID', (req, res) => {
res.setHeader('content-type', 'application/json')
//res.send(data.code, {status: data.status, message: 'this should update the specified resource'})
res.end()
})

/* The DELETE method removes the resource at the specified URL. */
server.del('/lists/:listID', (req, res) => {
res.setHeader('content-type', 'application/json')
//res.send(data.code, {status: data.status, message: 'this should delete the specified resource'})
res.end()
})

const port = process.env.PORT || 8080
server.listen(port, err => {
if (err) {
console.error(err)
} else {
console.log('App is ready at : ' + port)
}
})
File renamed without changes.
@@ -0,0 +1,25 @@
{
"name": "todo",
"version": "1.0.0",
"description": "Simple API to maintain to do lists.",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"keywords": [
"api",
"restify",
"tutorial"
],
"author": "Mark J Tyers",
"license": "ISC",
"dependencies": {
"csprng": "^0.1.1",
"restify": "^4.0.3",
"xmlbuilder": "^3.1.0"
},
"devDependencies": {
"frisby": "^0.8.5",
"jasmine-node": "^1.14.5"
}
}

0 comments on commit 433c905

Please sign in to comment.