From 065b87987f7ff215a43fc701c65fe86a7fc46aae Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 16:59:18 -0800 Subject: [PATCH 01/17] Base project files --- .eslintrc | 21 +++++++++ .gitignore | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + gulpfile.js | 24 ++++++++++ package.json | 29 ++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 .eslintrc create mode 100644 .gitignore create mode 100644 README.md create mode 100644 gulpfile.js create mode 100644 package.json diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..8dc6807 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "rules": { + "no-console": "off", + "indent": [ "error", 2 ], + "quotes": [ "error", "single" ], + "semi": ["error", "always"], + "linebreak-style": [ "error", "unix" ] + }, + "env": { + "es6": true, + "node": true, + "mocha": true, + "jasmine": true + }, + "ecmaFeatures": { + "modules": true, + "experimentalObjectRestSpread": true, + "impliedStrict": true + }, + "extends": "eslint:recommended" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..acdfab2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,127 @@ + +# Created by https://www.gitignore.io/api/node,macos,vim,windows,linux + +### Node ### +node_modules +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + + + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon +# Thumbnails +._* +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### Vim ### +# swap +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags + + +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### Linux ### + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* diff --git a/README.md b/README.md new file mode 100644 index 0000000..e369683 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# templates +Collection of useful files to re-use. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..eb26043 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,24 @@ +'use strict'; + +const gulp = require('gulp'); +const eslint = require('gulp-eslint'); +const mocha = require('gulp-mocha'); + +gulp.task('lint', function() { + gulp.src([ '**/*.js', '!node_modules/**']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + +gulp.task('test', function() { + gulp.src('./test/*.js', { read: false }) + .pipe(mocha({ reporter: 'spec'})); + //TODO: Try nyan reporter. +}); + +gulp.task('dev', function() { + gulp.watch(['**/*.js', '!node_modules/**'], ['lint', 'test']); +}); + +gulp.task('default', ['dev']); diff --git a/package.json b/package.json new file mode 100644 index 0000000..08bbb75 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "templates", + "version": "1.0.0", + "description": "Base files for node.js projects", + "main": "index.js", + "scripts": { + "test": "gulp test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/geoffsimons/templates.git" + }, + "keywords": [ + "nodejs", + "template" + ], + "author": "Geoff Simons", + "license": "ISC", + "bugs": { + "url": "https://github.com/geoffsimons/templates/issues" + }, + "homepage": "https://github.com/geoffsimons/templates#readme", + "devDependencies": { + "chai": "^3.5.0", + "gulp": "^3.9.1", + "gulp-eslint": "^3.0.1", + "gulp-mocha": "^3.0.1" + } +} From 0568ee19c5954b0caf36a65a887e8eb38fcedf51 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 18:29:49 -0800 Subject: [PATCH 02/17] Initial implementation --- model/router.js | 40 ++++++++++++++++++++++++++++++++++++++++ server.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 model/router.js create mode 100644 server.js diff --git a/model/router.js b/model/router.js new file mode 100644 index 0000000..016572c --- /dev/null +++ b/model/router.js @@ -0,0 +1,40 @@ +'use strict'; + +module.exports = exports = {}; + +const routes = []; + +exports.add = function(method, path, handler) { + var found = routes.find(function(route) { + return (route.method == method && route.path == path); + }); + if(found) { + //Update existing route's handler. + found.handler = handler; + return found; + } + //TODO: Is it worthwhile to make a Route constructor? + routes.push({ + method: method, + path: path, + handler: handler + }); +}; + +exports.find = function(method, path) { + var found = routes.find(function(route) { + return (route.method == method && route.path == path); + }); + if(found) return found.handler; +}; + +//TODO: Alternative impl for find +exports.find2 = function(method, path, callback) { + routes.forEach(function(route) { + if(route.method == method && route.path == path) { + callback(route.handler); + } + }); +}; + +//TODO: implement Array.prototype.find to see if I can match functionality diff --git a/server.js b/server.js new file mode 100644 index 0000000..d234b2f --- /dev/null +++ b/server.js @@ -0,0 +1,37 @@ +'use strict'; + +const http = require('http'); +const url = require('url'); +const querystring = require('querystring'); + +const PORT = process.env.PORT || 5555; + +const router = require('./model/router.js'); + +router.add('GET', '/', function(req, res) { + res.write('hey there. This is the base path.\n'); + res.end(); +}); + +//TODO: Q: Should we start using (req, res) => ? +const server = http.createServer(function(req, res) { + //Convert the url into an object. + req.url = url.parse(req.url); + //Decode the query string + req.url.query = querystring.parse(req.url.query); + + //TODO: see if we have a handler for method && path + // We can let the router try to handle the request. + // If it can't find a route, callback('no route found') + // If route is found, eventually callback(null, ???) + var handler = router.find(req.method, req.url.path); + + if(handler) return handler(req, res); + + res.write('This should be a 404. Route not found.\n'); + res.end(); +}); + +server.listen(PORT, () => { + console.log('cowsay server up', PORT); +}); From f918bec8d583db17c2fc12ba785d76b58931e06b Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 18:58:23 -0800 Subject: [PATCH 03/17] Added cowsay dependency --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 08bbb75..718eb33 100644 --- a/package.json +++ b/package.json @@ -25,5 +25,8 @@ "gulp": "^3.9.1", "gulp-eslint": "^3.0.1", "gulp-mocha": "^3.0.1" + }, + "dependencies": { + "cowsay": "^1.1.9" } } From d0ed4caad7cefcd511b490079dd61e1cd6a8faa3 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 18:58:56 -0800 Subject: [PATCH 04/17] Cleanup and TODO --- model/router.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/model/router.js b/model/router.js index 016572c..e3abe92 100644 --- a/model/router.js +++ b/model/router.js @@ -6,6 +6,7 @@ const routes = []; exports.add = function(method, path, handler) { var found = routes.find(function(route) { + //TODO: Add support for regex and/or glob specs return (route.method == method && route.path == path); }); if(found) { @@ -28,13 +29,4 @@ exports.find = function(method, path) { if(found) return found.handler; }; -//TODO: Alternative impl for find -exports.find2 = function(method, path, callback) { - routes.forEach(function(route) { - if(route.method == method && route.path == path) { - callback(route.handler); - } - }); -}; - //TODO: implement Array.prototype.find to see if I can match functionality From 7ed38cf2d6dd0add3a5d11d8576fdc83ef13a6e1 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 19:00:05 -0800 Subject: [PATCH 05/17] Initial impl --- lib/parse-body.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/parse-body.js diff --git a/lib/parse-body.js b/lib/parse-body.js new file mode 100644 index 0000000..f4713bd --- /dev/null +++ b/lib/parse-body.js @@ -0,0 +1,17 @@ +'use strict'; + +module.exports = function(req, callback) { + req.on('data', data => { + req.body = req.body || ''; + req.body += data.toString(); + }); + + req.on('end', () => { + try { + req.body = JSON.parse(req.body); + callback(null, req.body); + } catch(err) { + callback(err); + } + }); +}; From b94fbba00b704cee0464ccf44d5b9c773ce63bd3 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 19:01:21 -0800 Subject: [PATCH 06/17] added cowsay --- server.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index d234b2f..8690ce9 100644 --- a/server.js +++ b/server.js @@ -3,13 +3,30 @@ const http = require('http'); const url = require('url'); const querystring = require('querystring'); +const cowsay = require('cowsay'); const PORT = process.env.PORT || 5555; const router = require('./model/router.js'); router.add('GET', '/', function(req, res) { - res.write('hey there. This is the base path.\n'); + res.write('hello from my server!\n'); + res.end(); +}); + +router.add('GET', '/cowsay', function(req, res) { + console.log('GET /cowsay'); + let q = req.url.query.text; + let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; + // res.write('You are trying to GET to /cowsay...\n'); + msg = cowsay.say({ text: msg}); + res.write(msg + '\n'); + res.end(); +}); + +router.add('POST', '/cowsay', function(req, res) { + console.log('POST /cowsay'); + res.write('You are trying to POST to /cowsay...\n'); res.end(); }); @@ -20,12 +37,9 @@ const server = http.createServer(function(req, res) { //Decode the query string req.url.query = querystring.parse(req.url.query); - //TODO: see if we have a handler for method && path - // We can let the router try to handle the request. - // If it can't find a route, callback('no route found') - // If route is found, eventually callback(null, ???) - var handler = router.find(req.method, req.url.path); + console.log(req.url); + var handler = router.find(req.method, req.url.pathname); if(handler) return handler(req, res); res.write('This should be a 404. Route not found.\n'); From f5a7f385b9919f7953683a3f1e4da2a663ea9ebf Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 19:11:15 -0800 Subject: [PATCH 07/17] Found the dragon --- server.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 8690ce9..e61754a 100644 --- a/server.js +++ b/server.js @@ -19,7 +19,12 @@ router.add('GET', '/cowsay', function(req, res) { let q = req.url.query.text; let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; // res.write('You are trying to GET to /cowsay...\n'); - msg = cowsay.say({ text: msg}); + msg = cowsay.say({ + text: msg, + f: 'dragon', + e: '--', + T: 'Y' + }); res.write(msg + '\n'); res.end(); }); From 0639ab9f1c7a06ff853a595f2cd15ccde89c87b6 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 20:43:12 -0800 Subject: [PATCH 08/17] Added body parsing on POST methods --- server.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index e61754a..326836d 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ const cowsay = require('cowsay'); const PORT = process.env.PORT || 5555; const router = require('./model/router.js'); +const parseBody = require('./lib/parse-body.js'); router.add('GET', '/', function(req, res) { res.write('hello from my server!\n'); @@ -44,12 +45,30 @@ const server = http.createServer(function(req, res) { console.log(req.url); + if(req.method === 'POST') { + return parseBody(req, (err, body) => { + if(err) return handleErr(err, req, res); + console.log('parsed body:',body); + handleRoute(req, res); + }); + } + //On non-POST reqs, we still use handleRoute. + handleRoute(req, res); +}); + +function handleRoute(req, res) { var handler = router.find(req.method, req.url.pathname); if(handler) return handler(req, res); res.write('This should be a 404. Route not found.\n'); res.end(); -}); +} + +//TODO: Q: Do I need req? What might we do with that? +function handleErr(err, req, res) { + res.write(`Error: ${err}`); + res.end(); +} server.listen(PORT, () => { console.log('cowsay server up', PORT); From df6f65123810c33427ec6cb16974813abb82ea32 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 21:28:29 -0800 Subject: [PATCH 09/17] Error check for missing text field --- server.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 326836d..3848120 100644 --- a/server.js +++ b/server.js @@ -32,8 +32,19 @@ router.add('GET', '/cowsay', function(req, res) { router.add('POST', '/cowsay', function(req, res) { console.log('POST /cowsay'); - res.write('You are trying to POST to /cowsay...\n'); + //For now, I'm just going to pass the body to cowsay + if(!req.body || !req.body.text || req.body.text.length <= 0) { + console.log('body is missing "text"'); + return handleErr('Cannot find valid "text" param in POST body', req, res); + + //TODO: handleErr(options -> { status, statusMessage }) + } + + let msg = cowsay.say(req.body); + console.log('about to send:', msg); + res.write(msg + '\n'); res.end(); + console.log('...done sending'); }); //TODO: Q: Should we start using (req, res) => ? @@ -46,6 +57,7 @@ const server = http.createServer(function(req, res) { console.log(req.url); if(req.method === 'POST') { + console.log('parsing body...'); return parseBody(req, (err, body) => { if(err) return handleErr(err, req, res); console.log('parsed body:',body); @@ -66,8 +78,11 @@ function handleRoute(req, res) { //TODO: Q: Do I need req? What might we do with that? function handleErr(err, req, res) { - res.write(`Error: ${err}`); + console.log('handleErr:',err); + // console.log(res); + res.write(`Error: ${err}\n`); res.end(); + console.log('...wrote err msg'); } server.listen(PORT, () => { From 5310427aba5abf41558118b2608bdfdab7b3b9b4 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 22:05:44 -0800 Subject: [PATCH 10/17] Rename to indicate constructor --- model/{router.js => router-constructor.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename model/{router.js => router-constructor.js} (100%) diff --git a/model/router.js b/model/router-constructor.js similarity index 100% rename from model/router.js rename to model/router-constructor.js From b3f41d80fdb635a8110843e6b77d8b708f1ea338 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 22:42:36 -0800 Subject: [PATCH 11/17] Added util methods to res --- model/router-constructor.js | 29 ++++++++---- router.js | 41 ++++++++++++++++ server.js | 94 ++++++++++++++----------------------- 3 files changed, 96 insertions(+), 68 deletions(-) create mode 100644 router.js diff --git a/model/router-constructor.js b/model/router-constructor.js index e3abe92..dd3e525 100644 --- a/model/router-constructor.js +++ b/model/router-constructor.js @@ -1,11 +1,11 @@ 'use strict'; -module.exports = exports = {}; - -const routes = []; +function Router() { + this.routes = []; +} -exports.add = function(method, path, handler) { - var found = routes.find(function(route) { +Router.prototype.add = function(method, path, handler) { + var found = this.routes.find(function(route) { //TODO: Add support for regex and/or glob specs return (route.method == method && route.path == path); }); @@ -15,18 +15,31 @@ exports.add = function(method, path, handler) { return found; } //TODO: Is it worthwhile to make a Route constructor? - routes.push({ + this.routes.push({ method: method, path: path, handler: handler }); }; -exports.find = function(method, path) { - var found = routes.find(function(route) { +Router.prototype.find = function(method, path) { + var found = this.routes.find(function(route) { return (route.method == method && route.path == path); }); if(found) return found.handler; }; +Router.prototype.handle = function(req, res, next) { + var handler = this.find(req.method, req.url.pathname); + if(handler) return handler(req, res); + + if(next) return next(req, res); + + //Without a next handler, what can we do? + res.err({ status: 404, statusMessage: 'route not found'}); +}; + +module.exports = exports = {}; +exports.Router = Router; + //TODO: implement Array.prototype.find to see if I can match functionality diff --git a/router.js b/router.js new file mode 100644 index 0000000..221f4ab --- /dev/null +++ b/router.js @@ -0,0 +1,41 @@ +'use strict'; + +//TODO: Refactor all the cowsay routes into a cowsay module. +const cowsay = require('cowsay'); + +const Router = require('./model/router-constructor.js').Router; +const router = new Router(); + +router.add('GET', '/', function(req, res) { + res.send('hello from my server!'); +}); + +//TODO: Refactor all the cowsay routes into a cowsay module. +router.add('GET', '/cowsay', function(req, res) { + console.log('GET /cowsay'); + let q = req.url.query.text; + let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; + msg = cowsay.say({ + text: msg, + f: 'dragon', + e: '--', + T: 'Y' + }); + res.send(msg); +}); + +//TODO: Refactor all the cowsay routes into a cowsay module. +router.add('POST', '/cowsay', function(req, res) { + console.log('POST /cowsay'); + //For now, I'm just going to pass the body to cowsay + if(!req.body || !req.body.text || req.body.text.length <= 0) { + console.log('body is missing "text"'); + // return handleErr('Cannot find valid "text" param in POST body', req, res); + return res.err('Cannot find valid "text" param in POST body', req, res); + } + + let msg = cowsay.say(req.body); + res.send(msg); +}); + +module.exports = router; diff --git a/server.js b/server.js index 3848120..1982d28 100644 --- a/server.js +++ b/server.js @@ -3,50 +3,12 @@ const http = require('http'); const url = require('url'); const querystring = require('querystring'); -const cowsay = require('cowsay'); const PORT = process.env.PORT || 5555; -const router = require('./model/router.js'); +const router = require('./router.js'); const parseBody = require('./lib/parse-body.js'); -router.add('GET', '/', function(req, res) { - res.write('hello from my server!\n'); - res.end(); -}); - -router.add('GET', '/cowsay', function(req, res) { - console.log('GET /cowsay'); - let q = req.url.query.text; - let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; - // res.write('You are trying to GET to /cowsay...\n'); - msg = cowsay.say({ - text: msg, - f: 'dragon', - e: '--', - T: 'Y' - }); - res.write(msg + '\n'); - res.end(); -}); - -router.add('POST', '/cowsay', function(req, res) { - console.log('POST /cowsay'); - //For now, I'm just going to pass the body to cowsay - if(!req.body || !req.body.text || req.body.text.length <= 0) { - console.log('body is missing "text"'); - return handleErr('Cannot find valid "text" param in POST body', req, res); - - //TODO: handleErr(options -> { status, statusMessage }) - } - - let msg = cowsay.say(req.body); - console.log('about to send:', msg); - res.write(msg + '\n'); - res.end(); - console.log('...done sending'); -}); - //TODO: Q: Should we start using (req, res) => ? const server = http.createServer(function(req, res) { //Convert the url into an object. @@ -56,35 +18,47 @@ const server = http.createServer(function(req, res) { console.log(req.url); + //I'm attaching a couple of utility methods to res + res.send = function(msg) { + //set the headers, if any. + //also get the status from the res. + //TODO: What is the default status code? + res.writeHead(res.status || 200, res.statusMessage || 'OK', res.headers); + + console.log('about to send:', msg); + res.write(msg + '\n'); + res.end(); //After this, no more writes allowed! + console.log('...done sending'); + }; + + res.json = function(obj) { + res.headers['Content-Type'] = 'application/json'; + this.send(JSON.stringify(obj, null, 2)); + }; + + res.err = function(err) { + console.log('res.err:', err); + res.status = err.status || 500; + res.statusMessage = err.statusMessage || 'Internal server error'; + + this.json({ error: err }); + }; + + res.headers = { + 'Content-Type': 'text/plain' + }; + if(req.method === 'POST') { console.log('parsing body...'); return parseBody(req, (err, body) => { - if(err) return handleErr(err, req, res); + if(err) return res.err(err); console.log('parsed body:',body); - handleRoute(req, res); + router.handle(req, res); }); } - //On non-POST reqs, we still use handleRoute. - handleRoute(req, res); + router.handle(req, res); }); -function handleRoute(req, res) { - var handler = router.find(req.method, req.url.pathname); - if(handler) return handler(req, res); - - res.write('This should be a 404. Route not found.\n'); - res.end(); -} - -//TODO: Q: Do I need req? What might we do with that? -function handleErr(err, req, res) { - console.log('handleErr:',err); - // console.log(res); - res.write(`Error: ${err}\n`); - res.end(); - console.log('...wrote err msg'); -} - server.listen(PORT, () => { console.log('cowsay server up', PORT); }); From fda7db833b27ad1b74f7ecfe9bb0ab3d0555ef2f Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 22:57:26 -0800 Subject: [PATCH 12/17] Handling for bad query text --- router.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/router.js b/router.js index 221f4ab..84c4558 100644 --- a/router.js +++ b/router.js @@ -13,13 +13,17 @@ router.add('GET', '/', function(req, res) { //TODO: Refactor all the cowsay routes into a cowsay module. router.add('GET', '/cowsay', function(req, res) { console.log('GET /cowsay'); + let q = req.url.query.text; - let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; - msg = cowsay.say({ - text: msg, - f: 'dragon', - e: '--', - T: 'Y' + if(!q || q.length == 0) { + res.status = 400; + res.statusMessage = 'bad request'; + return res.send(cowsay.say({ text: 'bad request' })); + } + // let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; + let msg = cowsay.say({ + text: q, + f: req.url.query.f || 'beavis.zen' }); res.send(msg); }); From cc34fa305132cb3040dc2f82de84f853f31a725c Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 23:11:56 -0800 Subject: [PATCH 13/17] say helper handles bad reqs --- README.md | 5 +++-- router.js | 31 +++++++++++-------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index e369683..f13013d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# templates -Collection of useful files to re-use. +# Cowsay HTTP Server + +The cowsay module is a fun module for wrapping text. diff --git a/router.js b/router.js index 84c4558..1c22d15 100644 --- a/router.js +++ b/router.js @@ -1,6 +1,5 @@ 'use strict'; -//TODO: Refactor all the cowsay routes into a cowsay module. const cowsay = require('cowsay'); const Router = require('./model/router-constructor.js').Router; @@ -10,36 +9,28 @@ router.add('GET', '/', function(req, res) { res.send('hello from my server!'); }); -//TODO: Refactor all the cowsay routes into a cowsay module. -router.add('GET', '/cowsay', function(req, res) { - console.log('GET /cowsay'); - - let q = req.url.query.text; - if(!q || q.length == 0) { +function say(params, res) { + let text = params.text; + if(!text || text.length == 0) { res.status = 400; res.statusMessage = 'bad request'; return res.send(cowsay.say({ text: 'bad request' })); } - // let msg = (q && q.length > 0) ? q : 'text=Tell me what to say'; let msg = cowsay.say({ - text: q, - f: req.url.query.f || 'beavis.zen' + text: text, + f: params.f || 'beavis.zen' }); res.send(msg); +} + +router.add('GET', '/cowsay', function(req, res) { + console.log('GET /cowsay'); + say(req.url.query, res); }); -//TODO: Refactor all the cowsay routes into a cowsay module. router.add('POST', '/cowsay', function(req, res) { console.log('POST /cowsay'); - //For now, I'm just going to pass the body to cowsay - if(!req.body || !req.body.text || req.body.text.length <= 0) { - console.log('body is missing "text"'); - // return handleErr('Cannot find valid "text" param in POST body', req, res); - return res.err('Cannot find valid "text" param in POST body', req, res); - } - - let msg = cowsay.say(req.body); - res.send(msg); + say(req.body, res); }); module.exports = router; From 8939bfacd98721cfebef58987937c4f3c30dcc71 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 23:26:01 -0800 Subject: [PATCH 14/17] Added description and usage --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f13013d..06bd610 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ # Cowsay HTTP Server -The cowsay module is a fun module for wrapping text. +The cowsay module is a fun module for wrapping text. + +# How to install + +- Clone this repository, run `git clone https://github.com/geoffsimons/07-vanilla-http-server.git` +- Run `npm i` to install dependencies +- To startup the server: `node server.js` + +# API + +This server follows RESTful ideology, with the following routes: +* GET / +--Get a greeting as text/plain +* GET /cowsay?text=Something+to+say[&f=] +- `text` should be a URL encoded string to wrap +- `f` is what cow you want to have speak +* POST /cowsay +```json +{ + text: 'Something to say (REQUIRED)', + f: 'beavis.zen' +} +``` +See the cowsay docs for more cow names. +https://github.com/piuccio/cowsay/tree/master/cows From 4f792279a22618a0b5d634a325f7b185ada796d0 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 23:27:52 -0800 Subject: [PATCH 15/17] better json colors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06bd610..abed196 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This server follows RESTful ideology, with the following routes: - `text` should be a URL encoded string to wrap - `f` is what cow you want to have speak * POST /cowsay -```json +```js { text: 'Something to say (REQUIRED)', f: 'beavis.zen' From 90998a04153c2ac9e557074ddcf7e65e994c7756 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 23:33:09 -0800 Subject: [PATCH 16/17] Moved into lab-geoff --- .eslintrc => lab-geoff/.eslintrc | 0 .gitignore => lab-geoff/.gitignore | 0 README.md => lab-geoff/README.md | 0 gulpfile.js => lab-geoff/gulpfile.js | 0 {lib => lab-geoff/lib}/parse-body.js | 0 {model => lab-geoff/model}/router-constructor.js | 0 package.json => lab-geoff/package.json | 0 router.js => lab-geoff/router.js | 0 server.js => lab-geoff/server.js | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename .eslintrc => lab-geoff/.eslintrc (100%) rename .gitignore => lab-geoff/.gitignore (100%) rename README.md => lab-geoff/README.md (100%) rename gulpfile.js => lab-geoff/gulpfile.js (100%) rename {lib => lab-geoff/lib}/parse-body.js (100%) rename {model => lab-geoff/model}/router-constructor.js (100%) rename package.json => lab-geoff/package.json (100%) rename router.js => lab-geoff/router.js (100%) rename server.js => lab-geoff/server.js (100%) diff --git a/.eslintrc b/lab-geoff/.eslintrc similarity index 100% rename from .eslintrc rename to lab-geoff/.eslintrc diff --git a/.gitignore b/lab-geoff/.gitignore similarity index 100% rename from .gitignore rename to lab-geoff/.gitignore diff --git a/README.md b/lab-geoff/README.md similarity index 100% rename from README.md rename to lab-geoff/README.md diff --git a/gulpfile.js b/lab-geoff/gulpfile.js similarity index 100% rename from gulpfile.js rename to lab-geoff/gulpfile.js diff --git a/lib/parse-body.js b/lab-geoff/lib/parse-body.js similarity index 100% rename from lib/parse-body.js rename to lab-geoff/lib/parse-body.js diff --git a/model/router-constructor.js b/lab-geoff/model/router-constructor.js similarity index 100% rename from model/router-constructor.js rename to lab-geoff/model/router-constructor.js diff --git a/package.json b/lab-geoff/package.json similarity index 100% rename from package.json rename to lab-geoff/package.json diff --git a/router.js b/lab-geoff/router.js similarity index 100% rename from router.js rename to lab-geoff/router.js diff --git a/server.js b/lab-geoff/server.js similarity index 100% rename from server.js rename to lab-geoff/server.js From 1a1e972a04d088ca46115c943e1e46128da5bcc9 Mon Sep 17 00:00:00 2001 From: Geoff Simons Date: Tue, 13 Dec 2016 23:50:50 -0800 Subject: [PATCH 17/17] Update to README and quieter logging --- lab-geoff/README.md | 11 ++++++++--- lab-geoff/model/router-constructor.js | 2 +- lab-geoff/router.js | 2 -- lab-geoff/server.js | 9 --------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lab-geoff/README.md b/lab-geoff/README.md index abed196..75082a5 100644 --- a/lab-geoff/README.md +++ b/lab-geoff/README.md @@ -4,9 +4,14 @@ The cowsay module is a fun module for wrapping text. # How to install -- Clone this repository, run `git clone https://github.com/geoffsimons/07-vanilla-http-server.git` -- Run `npm i` to install dependencies -- To startup the server: `node server.js` +```sh +git clone https://github.com/geoffsimons/07-vanilla-http-server.git +npm i +``` +- To startup the server: +```sh +node server.js +``` # API diff --git a/lab-geoff/model/router-constructor.js b/lab-geoff/model/router-constructor.js index dd3e525..3efdb7e 100644 --- a/lab-geoff/model/router-constructor.js +++ b/lab-geoff/model/router-constructor.js @@ -10,11 +10,11 @@ Router.prototype.add = function(method, path, handler) { return (route.method == method && route.path == path); }); if(found) { + //TODO: make a test that sets a route more than once //Update existing route's handler. found.handler = handler; return found; } - //TODO: Is it worthwhile to make a Route constructor? this.routes.push({ method: method, path: path, diff --git a/lab-geoff/router.js b/lab-geoff/router.js index 1c22d15..e7ca958 100644 --- a/lab-geoff/router.js +++ b/lab-geoff/router.js @@ -24,12 +24,10 @@ function say(params, res) { } router.add('GET', '/cowsay', function(req, res) { - console.log('GET /cowsay'); say(req.url.query, res); }); router.add('POST', '/cowsay', function(req, res) { - console.log('POST /cowsay'); say(req.body, res); }); diff --git a/lab-geoff/server.js b/lab-geoff/server.js index 1982d28..d7d4c48 100644 --- a/lab-geoff/server.js +++ b/lab-geoff/server.js @@ -11,18 +11,11 @@ const parseBody = require('./lib/parse-body.js'); //TODO: Q: Should we start using (req, res) => ? const server = http.createServer(function(req, res) { - //Convert the url into an object. req.url = url.parse(req.url); - //Decode the query string req.url.query = querystring.parse(req.url.query); - console.log(req.url); - //I'm attaching a couple of utility methods to res res.send = function(msg) { - //set the headers, if any. - //also get the status from the res. - //TODO: What is the default status code? res.writeHead(res.status || 200, res.statusMessage || 'OK', res.headers); console.log('about to send:', msg); @@ -37,7 +30,6 @@ const server = http.createServer(function(req, res) { }; res.err = function(err) { - console.log('res.err:', err); res.status = err.status || 500; res.statusMessage = err.statusMessage || 'Internal server error'; @@ -49,7 +41,6 @@ const server = http.createServer(function(req, res) { }; if(req.method === 'POST') { - console.log('parsing body...'); return parseBody(req, (err, body) => { if(err) return res.err(err); console.log('parsed body:',body);