diff --git a/README.md b/README.md index 1e2c8d4..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,6 +0,0 @@ -##Getting started -* `npm i` - -##Todo - -create a basic web server with expressthat can handle a GET request for whatever resource you'd like and whatever url you want. Navigate to that url in the browser and see if yuor resource is there. The solution is on the `step-1-fix` branch diff --git a/index.js b/index.js new file mode 100644 index 0000000..d164a97 --- /dev/null +++ b/index.js @@ -0,0 +1,15 @@ +// intro point for our server. +// PRO-TIP: if you have an index.js file +// on the root of a folder in node +// you can just require that folder and node will +// automatically require the index.js on the root + +// setup config first before anything by requiring it +var config = require('./server/config/config'); +var app = require('./server/server'); +var logger = require('./server/util/logger'); + +app.listen(config.port); +logger.log('listening on http://localhost:' + config.port); + + diff --git a/package.json b/package.json index ea99b7f..4f31f28 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,21 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "start": "nodemon index.js", + "test": "" }, "author": "", "license": "ISC", "dependencies": { "body-parser": "^1.13.2", + "colors": "^1.1.2", "express": "^4.13.1", "lodash": "^3.10.0", + "mongoose": "^4.0.8", "morgan": "^1.6.1" + }, + "devDependencies": { + "chai": "^3.2.0", + "supertest": "^1.0.1" } } diff --git a/server.js b/server.js deleted file mode 100644 index 80f064e..0000000 --- a/server.js +++ /dev/null @@ -1,4 +0,0 @@ -// TODO: create a basic server with express -// that can handle a GET request for what ever resource you'd like -// whatever url you want, and then navigate to that url in the browser and -// see if yuor resource is there. diff --git a/server/api/api.js b/server/api/api.js new file mode 100644 index 0000000..d438c24 --- /dev/null +++ b/server/api/api.js @@ -0,0 +1,9 @@ +var router = require('express').Router(); + +// api router will mount other routers +// for all our resources +router.use('/users', require('./user/userRoutes')); +router.use('/categories', require('./category/categoryRoutes')); +router.use('/posts', require('./post/postRoutes')); + +module.exports = router; diff --git a/server/api/category/categoryController.js b/server/api/category/categoryController.js new file mode 100644 index 0000000..c80a1a7 --- /dev/null +++ b/server/api/category/categoryController.js @@ -0,0 +1,52 @@ +var Category = require('./categoryModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + // use the id and attach the category to req +}; + +exports.get = function(req, res, next) { + +}; + +exports.getOne = function(req, res, next) { + var category = req.category; + res.json(category); +}; + +exports.put = function(req, res, next) { + var category = req.category; + + var update = req.body; + + _.merge(category, update); + + category.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newcategory = req.body; + + Category.create(newcategory) + .then(function(category) { + res.json(category); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.category.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; diff --git a/server/api/category/categoryModel.js b/server/api/category/categoryModel.js new file mode 100644 index 0000000..f974543 --- /dev/null +++ b/server/api/category/categoryModel.js @@ -0,0 +1,12 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var CategorySchema = new Schema({ + name: { + type: String, + required: true, + unique: true + } +}); + +module.exports = mongoose.model('category', CategorySchema); diff --git a/server/api/category/categoryRoutes.js b/server/api/category/categoryRoutes.js new file mode 100644 index 0000000..865443a --- /dev/null +++ b/server/api/category/categoryRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from user!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/api/post/postController.js b/server/api/post/postController.js new file mode 100644 index 0000000..fcc247d --- /dev/null +++ b/server/api/post/postController.js @@ -0,0 +1,62 @@ +var Post = require('./postModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + Post.findById(id) + .then(function(post) { + if (!post) { + next(new Error('No post with that id')); + } else { + req.post = post; + next(); + } + }, function(err) { + next(err); + }); +}; + +exports.get = function(req, res, next) { + // need to populate here +}; + +exports.getOne = function(req, res, next) { + var post = req.post; + res.json(post); +}; + +exports.put = function(req, res, next) { + var post = req.post; + + var update = req.body; + + _.merge(post, update); + + post.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newpost = req.body; + + Post.create(newpost) + .then(function(post) { + res.json(post); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.post.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; diff --git a/server/api/post/postModel.js b/server/api/post/postModel.js new file mode 100644 index 0000000..b2827eb --- /dev/null +++ b/server/api/post/postModel.js @@ -0,0 +1,21 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var PostSchema = new Schema({ + title: { + type: String, + required: true, + unique: true + }, + + text: { + type: String, + required: true + }, + // array of ids from the users + author: [{type: Schema.Types.ObjectId, ref: 'user'}], + + categories: [{type: Schema.Types.ObjectId, ref: 'category'}] +}); + +module.exports = mongoose.model('post', PostSchema); diff --git a/server/api/post/postRoutes.js b/server/api/post/postRoutes.js new file mode 100644 index 0000000..3671e47 --- /dev/null +++ b/server/api/post/postRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from post!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/api/user/userController.js b/server/api/user/userController.js new file mode 100644 index 0000000..8d0cf26 --- /dev/null +++ b/server/api/user/userController.js @@ -0,0 +1,66 @@ +var User = require('./userModel'); +var _ = require('lodash'); + +exports.params = function(req, res, next, id) { + User.findById(id) + .then(function(user) { + if (!user) { + next(new Error('No user with that id')); + } else { + req.user = user; + next(); + } + }, function(err) { + next(err); + }); +}; + +exports.get = function(req, res, next) { + User.find({}) + .then(function(users){ + res.json(users); + }, function(err){ + next(err); + }); +}; + +exports.getOne = function(req, res, next) { + // fix me +}; + +exports.put = function(req, res, next) { + var user = req.user; + + var update = req.body; + + _.merge(user, update); + + user.save(function(err, saved) { + if (err) { + next(err); + } else { + res.json(saved); + } + }) +}; + +exports.post = function(req, res, next) { + var newUser = req.body; + + User.create(newUser) + .then(function(user) { + res.json(user); + }, function(err) { + next(err); + }); +}; + +exports.delete = function(req, res, next) { + req.user.remove(function(err, removed) { + if (err) { + next(err); + } else { + res.json(removed); + } + }); +}; diff --git a/server/api/user/userModel.js b/server/api/user/userModel.js new file mode 100644 index 0000000..a46b880 --- /dev/null +++ b/server/api/user/userModel.js @@ -0,0 +1,12 @@ +var mongoose = require('mongoose'); +var Schema = mongoose.Schema; + +var UserSchema = new Schema({ + username: { + type: String, + unique: true, + required: true + } +}); + +module.exports = mongoose.model('user', UserSchema); diff --git a/server/api/user/userRoutes.js b/server/api/user/userRoutes.js new file mode 100644 index 0000000..865443a --- /dev/null +++ b/server/api/user/userRoutes.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var logger = require('../../util/logger'); + +// setup boilerplate route jsut to satisfy a request +// for building +router.route('/') + .get(function(req, res){ + logger.log('Hey from user!!'); + res.send({ok: true}); + }); + +module.exports = router; diff --git a/server/config/config.js b/server/config/config.js new file mode 100644 index 0000000..2a1adf9 --- /dev/null +++ b/server/config/config.js @@ -0,0 +1,29 @@ +var _ = require('lodash'); + +var config = { + dev: 'development', + test: 'testing', + prod: 'production', + port: process.env.PORT || 3000 +}; + +process.env.NODE_ENV = process.env.NODE_ENV || config.dev; +config.env = process.env.NODE_ENV; + +var envConfig; +// require could error out if +// the file don't exist so lets try this statement +// and fallback to an empty object if it does error out +try { + envConfig = require('./' + config.env); + // just making sure the require actually + // got something back :) + envConfig = envConfig || {}; +} catch(e) { + envConfig = {}; +} + +// merge the two config files together +// the envConfig file will overwrite properties +// on the config object +module.exports = _.merge(config, envConfig); diff --git a/server/config/development.js b/server/config/development.js new file mode 100644 index 0000000..1495217 --- /dev/null +++ b/server/config/development.js @@ -0,0 +1,7 @@ +module.exports = { + // enabled logging for development + logging: true, + db: { + url: 'mongodb://localhost/nodeblog' + } +}; diff --git a/server/config/production.js b/server/config/production.js new file mode 100644 index 0000000..eab9e02 --- /dev/null +++ b/server/config/production.js @@ -0,0 +1,4 @@ +module.exports = { + // disbable logging for production + logging: false +}; diff --git a/server/config/testing.js b/server/config/testing.js new file mode 100644 index 0000000..d9ff459 --- /dev/null +++ b/server/config/testing.js @@ -0,0 +1,7 @@ +module.exports = { + // disbable logging for testing + logging: false, + db: { + url: 'mongodb://localhost/nodeblog-test' + } +}; diff --git a/server/middleware/appMiddlware.js b/server/middleware/appMiddlware.js new file mode 100644 index 0000000..380a5d6 --- /dev/null +++ b/server/middleware/appMiddlware.js @@ -0,0 +1,9 @@ +var morgan = require('morgan'); +var bodyParser = require('body-parser'); +// setup global middleware here + +module.exports = function(app) { + app.use(morgan('dev')); + app.use(bodyParser.urlencoded({ extended: true })); + app.use(bodyParser.json()); +}; diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..8eda1f7 --- /dev/null +++ b/server/server.js @@ -0,0 +1,16 @@ +var express = require('express'); +var app = express(); +var api = require('./api/api'); +var config = require('./config/config'); +// db.url is different depending on NODE_ENV +require('mongoose').connect(config.db.url); + +// setup the app middlware +require('./middleware/appMiddlware')(app); + +// setup the api +app.use('/api/', api); +// set up global error handling + +// export the app for testing +module.exports = app; diff --git a/server/util/logger.js b/server/util/logger.js new file mode 100644 index 0000000..a741055 --- /dev/null +++ b/server/util/logger.js @@ -0,0 +1,40 @@ +// no var needed here, colors will attached colors +// to String.prototype +require('colors'); +var _ = require('lodash'); + +var config = require('../config/config'); + +// create a noop (no operation) function for when loggin is disabled +var noop = function(){}; +// check if loggin is enabled in the config +// if it is, then use console.log +// if not then noop +var consoleLog = config.logging ? console.log.bind(console) : noop; + +var logger = { + log: function() { + // arguments is an array like object with all the passed + // in arguments to this function + var args = _.toArray(arguments) + .map(function(arg) { + if(typeof arg === 'object') { + // turn the object to a string so we + // can log all the properties and color it + var string = JSON.stringify(arg, 2); + return string.magenta; + } else { + // coerce to string to color + arg+=''; + return arg.magenta; + } + }); + + // call either console.log or noop here + // with the console object as the context + // and the new colored args :) + consoleLog.apply(console, args); + } +}; + +module.exports = logger;