From 9f6d3cf126489e65075ba94fa3354c8dfd70ce83 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:30:57 -0800 Subject: [PATCH 01/12] Adding eslinter --- .eslintrc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .eslintrc 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" +} From ea8cf19f8e31cfab4ed81e9b2caa53c21038d99a Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:31:10 -0800 Subject: [PATCH 02/12] Adding .gitignore --- .gitignore | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d675f5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +# Created by https://www.gitignore.io/api/node,macos,vim,git + +### Node ### +# 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 + + +### Git ### +*.orig From e99968c99fcfc1a6bee6b0ef740b06b7425ce0b2 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:31:20 -0800 Subject: [PATCH 03/12] Adding README --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..acf9834 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +### Express Single Resource API + +This is a fun project where we created refactored our Vanilla REST API to use Express.js! Woo! + +### Get the Project Running + +To get this project running, type the following in your command line: + +1. `git clone https://github.com/brittdawn/11-express_single_resource_api.git` +2. `cd 11-express_single_resource_api.git` +3. `npm i` +4. `brew install httpie` +5. `node server.js` + +You will now see the phrase "server is up: 3000" if you have not already specified a port number. + +### Test the Vanilla REST API (POST) + +1. Open a new terminal located at the root of this project and type `http POST localhost:3000/api/song title="meow" description="meow meow"` +2. You should get a JSON response with a description, id, and title with a `200` status code, like this example: + +``` javascript +HTTP/1.1 200 OK +Connection: keep-alive +Content-Length: 86 +Content-Type: application/json; charset=utf-8 +Date: Tue, 20 Dec 2016 03:49:14 GMT +ETag: W/"56-eWDnWC1unrCb1RCpC08DRQ" +X-Powered-By: Express + +{ + "description": "meow meow", + "id": "465251f0-c667-11e6-979e-15e9bd7f18fe", + "title": "meow" +} +``` + +### Test the Vanilla REST API (GET) + +After making a POST, you can make a GET request. + +1. Copy the id from your POST request above. Add it as a querystring to your GET request, like this example: ` http localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe` + +2. You should get a JSON response with a description, id, and title with a `200` status code, like this example: + +``` javascript +HTTP/1.1 200 OK +Connection: keep-alive +Content-Length: 86 +Content-Type: application/json; charset=utf-8 +Date: Tue, 20 Dec 2016 03:49:38 GMT +ETag: W/"56-eWDnWC1unrCb1RCpC08DRQ" +X-Powered-By: Express + +{ + "description": "meow meow", + "id": "465251f0-c667-11e6-979e-15e9bd7f18fe", + "title": "meow" +} +``` + +### Test the Vanilla REST API (DELETE) + +After making a GET or a POST, you can make a DELETE request. + +1. Copy the id from your POST/GET request above. Add it as a querystring to your DELETE request, like this example: `http DELETE localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe` + +2. You should get a JSON response with a description, id, and title with a `200` status code, like this example: + +``` javascript +HTTP/1.1 200 OK +Connection: keep-alive +Content-Length: 0 +Content-Type: application/json +Date: Tue, 20 Dec 2016 03:49:50 GMT +X-Powered-By: Express +``` + +3. If you try a GET request now for the item you deleted, it should not be found. For example, with the item above: `http DELETE localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe`. Now if you will get this `404` (not found) response, because you deleted the item, yo: + +``` javascript +HTTP/1.1 404 Not Found +Connection: keep-alive +Content-Length: 13 +Content-Type: text/html; charset=utf-8 +Date: Tue, 20 Dec 2016 03:49:53 GMT +ETag: W/"d-8ImJlDOBcq5A9PkBq5sbQw" +X-Powered-By: Express + +NotFoundError +``` From a9074e6594f031610587cfdf3a2e924d1a566537 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:31:39 -0800 Subject: [PATCH 04/12] Adding data from tests and running API requests. --- data/song/2b1d6ef0-c663-11e6-8151-6362d73a0c82.json | 1 + data/song/35631ab0-c666-11e6-a436-95d49b074ebc.json | 1 + data/song/49774dc0-c669-11e6-ad46-89d8a403c76b.json | 1 + data/song/67471600-c664-11e6-87b9-896cdb3073c3.json | 1 + data/song/69f309e0-c669-11e6-90f6-2d65db8c1575.json | 1 + data/song/7233c540-c669-11e6-82ff-ad0cf937bc7a.json | 1 + data/song/7d419fd0-c668-11e6-b91c-f7697a602373.json | 1 + data/song/82a92e10-c669-11e6-9ac3-8731107568fe.json | 1 + data/song/908eeb50-c669-11e6-bbbb-1b1c4bcc18fd.json | 1 + data/song/9e84f1b0-c668-11e6-aa3d-8da8f38cd954.json | 1 + data/song/ac6c4020-c669-11e6-9b97-7b290993bf82.json | 1 + data/song/bbe40f10-c669-11e6-bafd-6b4f864ffd1a.json | 1 + data/song/d4e9b2d0-c669-11e6-a4b3-2ded427aa76c.json | 1 + data/song/e9a15930-c669-11e6-aab5-151730593493.json | 1 + data/song/ee6f34f0-c669-11e6-bd41-55f016c71ca6.json | 1 + 15 files changed, 15 insertions(+) create mode 100644 data/song/2b1d6ef0-c663-11e6-8151-6362d73a0c82.json create mode 100644 data/song/35631ab0-c666-11e6-a436-95d49b074ebc.json create mode 100644 data/song/49774dc0-c669-11e6-ad46-89d8a403c76b.json create mode 100644 data/song/67471600-c664-11e6-87b9-896cdb3073c3.json create mode 100644 data/song/69f309e0-c669-11e6-90f6-2d65db8c1575.json create mode 100644 data/song/7233c540-c669-11e6-82ff-ad0cf937bc7a.json create mode 100644 data/song/7d419fd0-c668-11e6-b91c-f7697a602373.json create mode 100644 data/song/82a92e10-c669-11e6-9ac3-8731107568fe.json create mode 100644 data/song/908eeb50-c669-11e6-bbbb-1b1c4bcc18fd.json create mode 100644 data/song/9e84f1b0-c668-11e6-aa3d-8da8f38cd954.json create mode 100644 data/song/ac6c4020-c669-11e6-9b97-7b290993bf82.json create mode 100644 data/song/bbe40f10-c669-11e6-bafd-6b4f864ffd1a.json create mode 100644 data/song/d4e9b2d0-c669-11e6-a4b3-2ded427aa76c.json create mode 100644 data/song/e9a15930-c669-11e6-aab5-151730593493.json create mode 100644 data/song/ee6f34f0-c669-11e6-bd41-55f016c71ca6.json diff --git a/data/song/2b1d6ef0-c663-11e6-8151-6362d73a0c82.json b/data/song/2b1d6ef0-c663-11e6-8151-6362d73a0c82.json new file mode 100644 index 0000000..dbbf6af --- /dev/null +++ b/data/song/2b1d6ef0-c663-11e6-8151-6362d73a0c82.json @@ -0,0 +1 @@ +{"id":"2b1d6ef0-c663-11e6-8151-6362d73a0c82","title":"meow","description":"meow meow"} \ No newline at end of file diff --git a/data/song/35631ab0-c666-11e6-a436-95d49b074ebc.json b/data/song/35631ab0-c666-11e6-a436-95d49b074ebc.json new file mode 100644 index 0000000..1c26492 --- /dev/null +++ b/data/song/35631ab0-c666-11e6-a436-95d49b074ebc.json @@ -0,0 +1 @@ +{"id":"35631ab0-c666-11e6-a436-95d49b074ebc","title":"meow","description":"meow meow"} \ No newline at end of file diff --git a/data/song/49774dc0-c669-11e6-ad46-89d8a403c76b.json b/data/song/49774dc0-c669-11e6-ad46-89d8a403c76b.json new file mode 100644 index 0000000..33eb683 --- /dev/null +++ b/data/song/49774dc0-c669-11e6-ad46-89d8a403c76b.json @@ -0,0 +1 @@ +{"id":"49774dc0-c669-11e6-ad46-89d8a403c76b","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/67471600-c664-11e6-87b9-896cdb3073c3.json b/data/song/67471600-c664-11e6-87b9-896cdb3073c3.json new file mode 100644 index 0000000..61edfc1 --- /dev/null +++ b/data/song/67471600-c664-11e6-87b9-896cdb3073c3.json @@ -0,0 +1 @@ +{"id":"67471600-c664-11e6-87b9-896cdb3073c3","title":"meow","description":"meow meow"} \ No newline at end of file diff --git a/data/song/69f309e0-c669-11e6-90f6-2d65db8c1575.json b/data/song/69f309e0-c669-11e6-90f6-2d65db8c1575.json new file mode 100644 index 0000000..532efcc --- /dev/null +++ b/data/song/69f309e0-c669-11e6-90f6-2d65db8c1575.json @@ -0,0 +1 @@ +{"id":"69f309e0-c669-11e6-90f6-2d65db8c1575","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/7233c540-c669-11e6-82ff-ad0cf937bc7a.json b/data/song/7233c540-c669-11e6-82ff-ad0cf937bc7a.json new file mode 100644 index 0000000..0040b6f --- /dev/null +++ b/data/song/7233c540-c669-11e6-82ff-ad0cf937bc7a.json @@ -0,0 +1 @@ +{"id":"7233c540-c669-11e6-82ff-ad0cf937bc7a","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/7d419fd0-c668-11e6-b91c-f7697a602373.json b/data/song/7d419fd0-c668-11e6-b91c-f7697a602373.json new file mode 100644 index 0000000..075e6b7 --- /dev/null +++ b/data/song/7d419fd0-c668-11e6-b91c-f7697a602373.json @@ -0,0 +1 @@ +{"id":"7d419fd0-c668-11e6-b91c-f7697a602373","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/82a92e10-c669-11e6-9ac3-8731107568fe.json b/data/song/82a92e10-c669-11e6-9ac3-8731107568fe.json new file mode 100644 index 0000000..373b1e9 --- /dev/null +++ b/data/song/82a92e10-c669-11e6-9ac3-8731107568fe.json @@ -0,0 +1 @@ +{"id":"82a92e10-c669-11e6-9ac3-8731107568fe","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/908eeb50-c669-11e6-bbbb-1b1c4bcc18fd.json b/data/song/908eeb50-c669-11e6-bbbb-1b1c4bcc18fd.json new file mode 100644 index 0000000..0169b63 --- /dev/null +++ b/data/song/908eeb50-c669-11e6-bbbb-1b1c4bcc18fd.json @@ -0,0 +1 @@ +{"id":"908eeb50-c669-11e6-bbbb-1b1c4bcc18fd","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/9e84f1b0-c668-11e6-aa3d-8da8f38cd954.json b/data/song/9e84f1b0-c668-11e6-aa3d-8da8f38cd954.json new file mode 100644 index 0000000..89c04bc --- /dev/null +++ b/data/song/9e84f1b0-c668-11e6-aa3d-8da8f38cd954.json @@ -0,0 +1 @@ +{"id":"9e84f1b0-c668-11e6-aa3d-8da8f38cd954","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/ac6c4020-c669-11e6-9b97-7b290993bf82.json b/data/song/ac6c4020-c669-11e6-9b97-7b290993bf82.json new file mode 100644 index 0000000..772bcc7 --- /dev/null +++ b/data/song/ac6c4020-c669-11e6-9b97-7b290993bf82.json @@ -0,0 +1 @@ +{"id":"ac6c4020-c669-11e6-9b97-7b290993bf82","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/bbe40f10-c669-11e6-bafd-6b4f864ffd1a.json b/data/song/bbe40f10-c669-11e6-bafd-6b4f864ffd1a.json new file mode 100644 index 0000000..130d863 --- /dev/null +++ b/data/song/bbe40f10-c669-11e6-bafd-6b4f864ffd1a.json @@ -0,0 +1 @@ +{"id":"bbe40f10-c669-11e6-bafd-6b4f864ffd1a","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/d4e9b2d0-c669-11e6-a4b3-2ded427aa76c.json b/data/song/d4e9b2d0-c669-11e6-a4b3-2ded427aa76c.json new file mode 100644 index 0000000..000679d --- /dev/null +++ b/data/song/d4e9b2d0-c669-11e6-a4b3-2ded427aa76c.json @@ -0,0 +1 @@ +{"id":"d4e9b2d0-c669-11e6-a4b3-2ded427aa76c","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/e9a15930-c669-11e6-aab5-151730593493.json b/data/song/e9a15930-c669-11e6-aab5-151730593493.json new file mode 100644 index 0000000..623460b --- /dev/null +++ b/data/song/e9a15930-c669-11e6-aab5-151730593493.json @@ -0,0 +1 @@ +{"id":"e9a15930-c669-11e6-aab5-151730593493","title":"test title","description":"test description"} \ No newline at end of file diff --git a/data/song/ee6f34f0-c669-11e6-bd41-55f016c71ca6.json b/data/song/ee6f34f0-c669-11e6-bd41-55f016c71ca6.json new file mode 100644 index 0000000..f517917 --- /dev/null +++ b/data/song/ee6f34f0-c669-11e6-bd41-55f016c71ca6.json @@ -0,0 +1 @@ +{"id":"ee6f34f0-c669-11e6-bd41-55f016c71ca6","title":"test title","description":"test description"} \ No newline at end of file From 065dbeb00fc9a204727b53c8d0ccfe2aff271783 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:31:50 -0800 Subject: [PATCH 05/12] Adding gulpfile.js --- gulpfile.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 gulpfile.js diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..6db050d --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,37 @@ +'use strict'; + +const gulp = require('gulp'); +const eslint = require('gulp-eslint'); +const mocha = require('gulp-mocha'); +const cache = require('gulp-cache'); +const istanbul = require('gulp-istanbul'); + +gulp.task('pre-test', function() { + return gulp.src(['./lib/*.js', './model/*.js', '!node_modules/**']) + .pipe(istanbul()) + .pipe(istanbul.hookRequire()); +}); + +gulp.task('test', ['pre-test'], function() { + gulp.src('./test/*-test.js', { read: false}) + .pipe(mocha({ report: 'spec'})) + .pipe(istanbul.writeReports()) + .pipe(istanbul.enforceThresholds({thresholds: {global: 90}})); +}); + +gulp.task('lint', function() { + return gulp.src(['**/*.js', '!node_modules/**']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + +gulp.task('dev', function() { + gulp.watch(['**/*.js', '!node_modules/**'], ['lint', 'test']); +}); + +gulp.task('default', ['dev']); + +gulp.task('clear', function (done) { + return cache.clearAll(done); +}); From 1c16bb12d0cddf8a2a9360ed2896996aaa6d95b5 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:32:07 -0800 Subject: [PATCH 06/12] Adding refactored storage.js --- lib/storage.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lib/storage.js diff --git a/lib/storage.js b/lib/storage.js new file mode 100644 index 0000000..51f8355 --- /dev/null +++ b/lib/storage.js @@ -0,0 +1,48 @@ +'use strict'; + +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs'), {suffix: 'Prom'}); +const createError = require('http-errors'); +const debug = require('debug')('song:storage'); + +module.exports = exports = {}; + +exports.createItem = function(schemaName, item){ + debug('createItem'); + + if (!schemaName) return Promise.reject(createError(400, 'expected the schema name')); + if (!item) return Promise.reject(createError(400, 'expected an item')); + + let json = JSON.stringify(item); + return fs.writeFileProm(`${__dirname}/../data/${schemaName}/${item.id}.json`, json) + .then( () => item) + .catch( err => Promise.reject(createError(500, err.message))); +}; + +exports.fetchItem = function(schemaName, id){ + debug('fetchItem'); + + if (!schemaName) return Promise.reject(createError(400, 'expected the schema name')); + if (!id) return Promise.reject(createError(400, 'expected an id')); + + return fs.readFileProm(`${__dirname}/../data/${schemaName}/${id}.json`) + .then(data => { + try { + let item = JSON.parse(data.toString()); + return item; + } catch (err) { + return Promise.reject(createError(500, err.message)); + } + }) + .catch(err => Promise.reject(createError(404, err.message))); +}; + +exports.deleteItem = function(schemaName, id) { + debug('deleteItem'); + + if (!schemaName) return Promise.reject(createError(400, 'expected the schema name')); + if (!id) return Promise.reject(createError(400, 'expected an id')); + + return fs.unlinkProm(`${__dirname}/../data/${schemaName}/${id}.json`) + .catch( err => Promise.reject(createError(500, err.message))); +}; From bcd96dd3068c01ae06006193019987faa4b4a0db Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:32:22 -0800 Subject: [PATCH 07/12] Adding refactoring songmodel. --- model/song.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 model/song.js diff --git a/model/song.js b/model/song.js new file mode 100644 index 0000000..addb501 --- /dev/null +++ b/model/song.js @@ -0,0 +1,38 @@ +'use strict'; + +const uuid = require('node-uuid'); +const createError = require('http-errors'); +const debug = require('debug')('song:song'); +const storage = require('../lib/storage.js'); + +const Song = module.exports = function(title, description) { + debug('song constructor'); + + if (!title) throw createError(400, 'expected title'); + if (!description) throw createError(400, 'expected description'); + + this.id = uuid.v1(); + this.title = title; + this.description = description; +}; + +Song.createSong = function(_song) { + debug('createSong'); + + try { + let song = new Song(_song.title, _song.description); + return storage.createItem('song', song); + } catch (err) { + return Promise.reject(err); + } +}; + +Song.fetchSong = function(id) { + debug('fetchSong'); + return storage.fetchItem('song', id); +}; + +Song.deleteSong = function(id) { + debug('deleteSong'); + return storage.deleteItem('song', id); +}; From e9556c949ff71d4c504c02590290a3c423798d60 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:32:47 -0800 Subject: [PATCH 08/12] Updating package.json with new dependencies and script. --- package.json | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..38345a9 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "express", + "version": "1.0.0", + "description": "This is a project using Express.", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "DEBUG='song*' node server.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "bluebird": "^3.4.6", + "body-parser": "^1.15.2", + "debug": "^2.4.5", + "express": "^4.14.0", + "http-errors": "^1.5.1", + "morgan": "^1.7.0", + "node-uuid": "^1.4.7" + }, + "devDependencies": { + "chai": "^3.5.0", + "eslint": "^3.12.2", + "gulp": "^3.9.1", + "gulp-cache": "^0.4.5", + "gulp-eslint": "^3.0.1", + "gulp-istanbul": "^1.1.1", + "gulp-mocha": "^3.0.1", + "mocha": "^3.2.0", + "superagent": "^3.3.0" + } +} From 94e761ac90e197307635b5e77fe7e9dbb4009b53 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:32:59 -0800 Subject: [PATCH 09/12] Refactoring server.js --- server.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 server.js diff --git a/server.js b/server.js new file mode 100644 index 0000000..fd36c5f --- /dev/null +++ b/server.js @@ -0,0 +1,56 @@ +'use strict'; + +const express = require('express'); +const morgan = require('morgan'); +const createError = require('http-errors'); +const jsonParser = require('body-parser').json(); +const debug = require('debug')('song:server'); + +const Song = require('./model/song'); +const storage = require('./lib/storage.js'); + +const PORT = process.env.PORT || 3000; +const app = express(); + +app.use(morgan('dev')); + +app.post('/api/song', jsonParser, function(req, res, next) { + debug('POST: /api/song'); + + Song.createSong(req.body) + .then( song => res.json(song)) + .catch( err => next(err)); +}); + +app.get('/api/song', function(req, res, next) { + debug('GET: /api/song'); + + Song.fetchSong(req.query.id) + .then( song => res.json(song)) + .catch( err => next(err)); +}); + +app.delete('/api/song', (req, res, next) => { + debug('DELETE: /api/song'); + + Song.deleteSong(req.query.id) + .then( song => res.json(song)) + .catch( err => next(err)); +}); + +app.use(function(err, req, res, next) { + debug('error middleware'); + console.error(err.message); + + if (err.status) { + res.status(err.status).send(err.name); + return; + } + + err = createError(500, err.message); + res.status(err.status).send(err.name); +}); + +app.listen(PORT, () => { + debug(`server up: ${PORT}`); +}); From 19416d2237176680872ee6b6ac7f1006b5b3ea42 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Mon, 19 Dec 2016 20:33:16 -0800 Subject: [PATCH 10/12] Adding tests --- test/song-route-test.js | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 test/song-route-test.js diff --git a/test/song-route-test.js b/test/song-route-test.js new file mode 100644 index 0000000..2e43e1a --- /dev/null +++ b/test/song-route-test.js @@ -0,0 +1,85 @@ +'use strict'; + +const request = require('superagent'); +const expect = require('chai').expect; + +require('../server.js'); + +describe('Song Routes', function() { + var song = null; + + describe('POST: /api/song', function() { + it('should return a 400 bad request if no body is given', function(done) { + request.post('localhost:3000/api/song') + .send({}) + .end((err, res) => { + expect(err).to.be.an('error'); + expect(res.text).to.equal('BadRequestError'); + expect(res.body.id).to.equal(undefined); + done(); + }); + }); + it('should return a 400 bad request an invalid body is requested', function(done) { + request.post('localhost:3000/api/song') + .send({ meow: 'meow meow meow', robot: 'beep beep boop' }) + .end((err, res) => { + expect(res.text).to.equal('BadRequestError'); + expect(res.body.id).to.equal(undefined); + done(); + }); + }); + it('should return a song', function(done) { + request.post('localhost:3000/api/song') + .send({ title: 'test title', description: 'test description' }) + .end((err, res) => { + if (err) return done(err); + expect(res.status).to.equal(200); + expect(res.body.title).to.equal('test title'); + expect(res.body.description).to.equal('test description'); + song = res.body; + done(); + }); + }); + }); + + describe('GET: /api/song', function() { + it('should return a song', function(done) { + request.get(`localhost:3000/api/song?id=${song.id}`) + .end((err, res) => { + if (err) return done(err); + expect(res.status).to.equal(200); + expect(res.body.title).to.equal('test title'); + expect(res.body.description).to.equal('test description'); + done(); + }); + }); + it('should return a 404 not found for a valid request but an invalid id', function(done) { + request.get('localhost:3000/api/song?id=44abc123') + .end((err, res) => { + expect(res.status).to.equal(404); + expect(res.text).to.equal('NotFoundError'); + done(); + }); + }); + it('should return a 400 bad request if id is not provided', function(done) { + request.get('localhost:3000/api/song') + .end((err, res) => { + expect(res.status).to.equal(400); + expect(res.text).to.equal('BadRequestError'); + expect(res.body.id).to.equal(undefined); + done(); + }); + }); + }); + + describe('testing for routes not registered', function() { + it('should return a status code of 404', function(done) { + request.get('localhost:3000/api/movie') + .end((err, res) => { + expect(res.status).to.equal(404); + expect(res.text).to.equal('Cannot GET /api/movie\n'); + done(); + }); + }); + }); +}); From e5cf55149294d55d4a8f6f2566416a5785514552 Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Tue, 20 Dec 2016 09:57:32 -0800 Subject: [PATCH 11/12] Cleaning up README. --- README.md | 8 ++++---- data/song/d13a1c10-c6dc-11e6-baaf-571a317fb498.json | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 data/song/d13a1c10-c6dc-11e6-baaf-571a317fb498.json diff --git a/README.md b/README.md index acf9834..00cda5d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### Express Single Resource API +## Express Single Resource API This is a fun project where we created refactored our Vanilla REST API to use Express.js! Woo! @@ -39,7 +39,7 @@ X-Powered-By: Express After making a POST, you can make a GET request. -1. Copy the id from your POST request above. Add it as a querystring to your GET request, like this example: ` http localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe` +1. Copy the id from your POST request above. Add it as a querystring to your GET request, like this example: `http localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe` 2. You should get a JSON response with a description, id, and title with a `200` status code, like this example: @@ -65,10 +65,10 @@ After making a GET or a POST, you can make a DELETE request. 1. Copy the id from your POST/GET request above. Add it as a querystring to your DELETE request, like this example: `http DELETE localhost:3000/api/song?id=465251f0-c667-11e6-979e-15e9bd7f18fe` -2. You should get a JSON response with a description, id, and title with a `200` status code, like this example: +2. You should get a JSON response with a description, id, and title, like this example: ``` javascript -HTTP/1.1 200 OK +HTTP/1.1 204 Connection: keep-alive Content-Length: 0 Content-Type: application/json diff --git a/data/song/d13a1c10-c6dc-11e6-baaf-571a317fb498.json b/data/song/d13a1c10-c6dc-11e6-baaf-571a317fb498.json new file mode 100644 index 0000000..4c52a8a --- /dev/null +++ b/data/song/d13a1c10-c6dc-11e6-baaf-571a317fb498.json @@ -0,0 +1 @@ +{"id":"d13a1c10-c6dc-11e6-baaf-571a317fb498","title":"test title","description":"test description"} \ No newline at end of file From 888e895b8641b849d4e4c7f907aad7e83e22bd2f Mon Sep 17 00:00:00 2001 From: Britt Dawn Date: Tue, 20 Dec 2016 10:41:46 -0800 Subject: [PATCH 12/12] Cleaning up linter errors. --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index fd36c5f..6e8b24f 100644 --- a/server.js +++ b/server.js @@ -7,7 +7,6 @@ const jsonParser = require('body-parser').json(); const debug = require('debug')('song:server'); const Song = require('./model/song'); -const storage = require('./lib/storage.js'); const PORT = process.env.PORT || 3000; const app = express(); @@ -38,6 +37,7 @@ app.delete('/api/song', (req, res, next) => { .catch( err => next(err)); }); +// eslint-disable-next-line app.use(function(err, req, res, next) { debug('error middleware'); console.error(err.message);