Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lab-kyler/gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const gulp = require('gulp');
//const fs = require('fs');
const eslint = require('gulp-eslint');
const mocha = require('gulp-mocha');

gulp.task('test', function() {
return gulp.src('./test/*-test.js', {read: false})
.pipe(mocha({reporter: 'spec'}));
});

gulp.task('lint', function() {
return gulp.src(['**/*.js', '!node_modules'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});

gulp.task('default', ['lint', 'test']);
7 changes: 7 additions & 0 deletions lab-kyler/lib/cors-middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

module.exports = function(req, res, next) {
res.append('Access-Control-Allow-Origin', '*');
res.append('Access-Control-Allow-Headers', '*');
next();
};
55 changes: 55 additions & 0 deletions lab-kyler/lib/diskStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'), {suffix: 'Prom'});
const createError = require('http-errors');
const debug = require('debug')('joke:storage');

module.exports = exports = {};

exports.storeItem = (schema, item) => {
debug('storeItem');
if (!schema) return Promise.reject(createError(400, 'expected schema'));
if (!item || !item.id) return Promise.reject(createError(400, 'expected item/item id'));

return fs.writeFileProm(`${__dirname}/../data/${schema}/${item.id}.json`, JSON.stringify(item))
.then( () => item)
.catch( err => Promise.reject(createError(500, err.message)));
};

exports.fetchItem = (schema, id) => {
debug('fetchItem method');
if (!schema) return Promise.reject(createError(400, 'expected schema'));
if (!id) return exports.enumerate(schema);

return fs.readFileProm(`${__dirname}/../data/${schema}/${id}.json`)
.then (data => {
try {
return JSON.parse(data.toString());
} catch (err) {
return Promise.reject(createError(500, err.message));
}
})
.catch ( () => Promise.reject(createError(404, 'not found')));
};

exports.enumerate = (schema) => {
debug('enumerate method');
if (!schema) return Promise.reject(createError(400, 'expected schema'));

return fs.readdirProm(`${__dirname}/../data/${schema}`)
.then( fileArray => fileArray.map(fileName => fileName.split('.json')[0]))
.catch( err => Promise.reject(createError(404, err.message)));
};

exports.deleteItem = (schema, id) => {
debug('deleteItem method');

if (!schema) return Promise.reject(createError(400, 'expected schema'));
if (!id) return Promise.reject(createError(400, 'expected id'));

var path = `${__dirname}/../data/${schema}/${id}.json`;
return fs.accessProm(path)
.then( () => fs.unlinkProm(path))
.catch(err => Promise.reject(createError(404, err.message)));
};
22 changes: 22 additions & 0 deletions lab-kyler/lib/error-middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

const createError = require('http-errors');
const debug = require('debug')('note:error-middleware');

module.exports = function(err, req, res, next) { //eslint-disable-line
console.error(err.message);

if(err.status) {
debug('user error');

res.status(err.status).send(err.name);
next();
return;
}

debug('server error');
err = createError(500, err.message);
res.status(err.status).send(err.name);
next();
return;
};
63 changes: 63 additions & 0 deletions lab-kyler/model/joke.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

const uuid = require('node-uuid');
const createError = require('http-errors');
const debug = require('debug')('joke:joke');
const storage = require('../lib/diskStorage.js');

const Joke = module.exports = function(setup, punchline) {
debug('Joke constructor');

if (!setup) throw createError(400, 'expected setup');
if (!punchline) throw createError(400, 'expected punchline');

this.id = uuid.v1();
this.setup = setup;
this.punchline = punchline;
};

Joke.createJoke = function(_joke) {
debug('createJoke method');

try {
let joke = new Joke(_joke.setup, _joke.punchline);
return storage.storeItem('joke', joke);
//console.log(newJoke);
//return newJoke;
} catch (err) {
return Promise.reject(err);
}
};

Joke.fetchJoke = function(id) {
debug('fetchJoke method');

return storage.fetchItem('joke', id);
};

Joke.updateJoke = function(id, _joke) {
debug('updateJoke method');

return storage.fetchItem('joke', id)
.catch( err => Promise.reject(createError(404, err.message)))
.then( joke => {

for (var prop in joke) {
if (prop === 'id') continue;
if (_joke[prop]) joke[prop] = _joke[prop];
}
return storage.storeItem('joke', joke);
});
};

Joke.deleteJoke = function(id) {
debug('deleteJoke method');

return storage.deleteItem('joke', id);
};

Joke.enumerate = function() {
debug('enumerate method');

return storage.enumerate('joke');
};
29 changes: 29 additions & 0 deletions lab-kyler/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "ic-express-api-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node server.js",
"debug": "DEBUG='joke*' nodemon server.js",
"test": "DEBUG='joke*' ./node_modules/mocha/bin/mocha"
},
"keywords": [],
"author": "",
"license": "ISC",
"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",
"mocha": "^3.2.0",
"nodemon": "^1.11.0",
"superagent": "^3.3.1"
}
}
22 changes: 22 additions & 0 deletions lab-kyler/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#Lab 12 - Single Resource Express API with middleware!

##About
This is a demo HTTP server using the express framework. You can GET, POST, PUT, and DELETE jokes which are stored on disk. Each joke is comprised of a setup string, a punchline string, and a random ID which is assigned when the joke is stored.

##Getting started
1. Install with `npm i`
2. Start in normal mode with `npm start` or debug mode with `npm run debug`.

Server runs on `$PORT` or defaults to 2000.

##Usage
* Store a joke:
* `http post localhost:2000/api/joke setup=<setup> punchline=<punchline>`
* Enumerate stored jokes as an array of joke IDs:
* `http get localhost:2000/api/joke`
* Retrieve a joke:
* `http get localhost:2000/api/joke?id=<id>`
* Update a joke:
* `http put localhost:2000/api/joke?id=<id> setup=<new setup> punchline=<new punchline>`
* Delete a joke:
* `http delete localhost:2000/api/joke/id=<id>`
49 changes: 49 additions & 0 deletions lab-kyler/route/joke-router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

const Router = require('express').Router; //express's router class
const jsonParser = require('body-parser').json(); //called because we will pass as middleware?
const debug = require('debug')('joke:joke-router');
const Joke = require('../model/joke.js');
const jokeRouter = new Router();

jokeRouter.post('/api/joke', jsonParser, function(req, res, next) {
debug('POST: /api/joke');

Joke.createJoke(req.body)
.then( joke => res.json(joke))
.catch( err => next(err));
});

jokeRouter.get('/api/joke/:id/', function(req, res, next) {
debug('GET: /api/joke/:id/');

Joke.fetchJoke(req.params.id)
.then( joke => res.json(joke))
.catch( err => next(err));
});

jokeRouter.get('/api/joke', function(req, res, next) {
debug('GET: /api/joke');

Joke.enumerate()
.then( list => res.json(list))
.catch(next); //will next(err) automatically
});

jokeRouter.put('/api/joke/', jsonParser, function(req, res, next) {
debug('PUT: /api/joke');

Joke.updateJoke(req.query.id, req.body) //doesn't use parameters like above.
.then( joke => res.json(joke))
.catch(next);
});

jokeRouter.delete('/api/joke/:id', function(req, res, next) {
debug('DELETE: /api/joke/:id');

Joke.deleteJoke(req.params.id) //doesn't use parameters like above.
.then( joke => res.json(joke))
.catch(next);
});

module.exports = jokeRouter; //this is an instantiated Router object, with our routes added.
21 changes: 21 additions & 0 deletions lab-kyler/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

const morgan = require('morgan');
const express = require('express');
//const createError = require('http-errors');
const cors = require('./lib/cors-middleware.js');
const errors = require('./lib/error-middleware.js');
const jokeRouter = require('./route/joke-router.js');
const debug = require('debug')('joke:server');

const PORT = process.env.PORT || 2000;
const app = express();

app.use(morgan('dev')); //this is where middleware gets passed in
app.use(cors);
app.use(jokeRouter); //route-level middleware, as app middleware.
app.use(errors);

app.listen(PORT, () => {
debug(`Server listening on port ${PORT}`);
});
Loading