- installation
npm install express --save
npm install -g express-generator
- running the above commands should enable a express function:
express AwesomeAnswers
npm install
-
package.json is where all the modules live
-
change the port to 5000 in bin/www file
var port = normalizePort(process.env.PORT || '5000');
app.set('port', port);
- to avoid restarting server when making code changes, install nodemon
npm install -g nodemon
- start server
nodemon bin/www
- notice the code generated in app.js, to tell the app that it is using the express library
var app = express();
- unlike sinatra that looks for view files in a view folder by convention, you need to configure this in node
- so in app.js file, the following code is generated
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
- the following is called middleware, handling for example authentications, cookieparsers
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
- setting up a middleware function, such as before filter for unauthenticated user to stop response
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
- in routes folder, make a file called question.js. create a route:
var express = require("express"),
router = express.Router();
router.get("/new", function(request, response, next){
response.end("Create New Question");
});
- every time when yo want to use the code elsewhere
modue.exports = router;
- go to app.js
var questions = require('./routes/questions');
app.use('/questions', questions);
- notice the layout view is also used in node. can optionally add in bootstrap link
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous")
body
block content
- monogdb
brew install mongodb
AwesomeAnswers $ mkdir /data
AwesomeAnswers $ mkdir /data/db
AwesomeAnswers $ whoami
jenniferli
AwesomeAnswers $ sudo chown jenniferli /data/db
AwesomeAnswers $ mongod
2016-03-09T11:37:54.089-0800 I CONTROL [initandlisten] MongoDB starting : pid=57760 port=27017 dbpath=/data/db 64-bit host=Jennifers-MacBook-Pro.local
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] db version v3.2.0
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] git version: 45d947729a0315accb6d4f15a6b06be6d9c19fe7
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] allocator: system
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] modules: none
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] build environment:
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] distarch: x86_64
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] target_arch: x86_64
2016-03-09T11:37:54.090-0800 I CONTROL [initandlisten] options: {}
2016-03-09T11:37:54.091-0800 I STORAGE [initandlisten] wiredtiger_open config: create,cache_size=9G,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
2016-03-09T11:37:54.346-0800 I NETWORK [HostnameCanonicalizationWorker] Starting hostname canonicalization worker
2016-03-09T11:37:54.346-0800 I FTDC [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'
2016-03-09T11:37:54.392-0800 I NETWORK [initandlisten] waiting for connections on port 27017
- install the mongoose module. it will allow node app to connect to mongo db
npm install mongoose --save
- create a model folder and inside this folder make a question.js file
var mongoose = require("mongoose"),
Schema = mongoose.Schema;
var QuestionSchema = new Schema({
title: {type: String},
body: {type: String}
});
var Question = mongoose.model("Question", QuestionSchema);
module.exports = Question;
###CRUD
- use method-verride to enable verbs other than post and get
npm install method-override
- questions.js in routes act as controller
var express = require("express"),
router = express.Router(),
Question = require("../models/question");
router.get("/new", function(request, response, next){
// response.end("Create New Question");
response.render("questions/new");
});
- go to view/questions create a file called new.jade
- note jade is space/indent specific
- create a simple question form
extends ../layout
block content
h1 Create New Question
form(action="/questions" method="POST")
.form-group(class="#{errors.title ? 'has-error' : ''}")
label(for="title") Title
input(type="text" id="title" name="title" class="form-control")
if errors.title
.help-block= errors.title
.form-group
label(for="body") Body
textarea(id="body" name="body" class="form-control")
input(type="submit" value="Create Question" class="btn btn-primary")
-
if only give a class without a tag name, div will be chosen by default
-
questions.js
router.get("/new", function(request, response, next){
// response.end("Create New Question");
response.render("questions/new", {errors: {}});
});
- questions.js
router.post("/", function(request, response, next){
var question = new Question({title: request.body.title,
body: request.body.body});
question.save(function(err, question){
if(err) {
response.render("questions/new", {errors: err.errors});
} else {
response.redirect("/questions/" + question._id);
}
});
});
router.get("/:id", function(req, res) {
Question.findOne({_id: req.params.id}, function(err, question){
if(err) {
res.render('error', {message: "Question not found",
error: {status: 404}});
} else {
res.render("questions/show", {question: question});
}
});
});
extends ../layout
block content
h1= question.title
p= question.body
a(href="/questions/#{question._id}/edit") Edit
form(action="/questions/#{question.id}?_method=delete" method="POST")
input(type="submit" value="Delete")
router.get("/:id/edit", function(req, res){
Question.findOne({_id: req.params.id}, function(err, question){
if(err) {
res.render('error', {message: "Question not found",
error: {status: 404}});
} else {
res.render("questions/edit", {question: question, errors: {}});
}
});
});
extends ../layout
block content
h1 Update Question
form(action="/questions/#{question._id}?_method=patch" method="POST")
.form-group(class="#{errors.title ? 'has-error' : ''}")
label(for="title") Title
input(type="text" id="title" name="title" class="form-control" value=question.title)
if errors.title
.help-block= errors.title
.form-group
label(for="body") Body
textarea(id="body" name="body" class="form-control")= question.body
input(type="submit" value="Update Question" class="btn btn-primary")
router.patch("/:id", function(req, res){
Question.findOne({_id: req.params.id}, function(err, question){
if(err) {
res.render('error', {message: "Question not found",
error: {status: 404}});
} else {
question.title = req.body.title;
question.body = req.body.body;
question.save(function(err){
if(err) {
res.render("questions/edit", {errors: err.errors, question: question});
} else {
res.redirect("/questions/" + question._id);
}
});
}
});
});
router.delete("/:id", function(req, res){
Question.remove({_id: req.params.id}, function(err, question){
if(err){
res.render('error', {message: "Question not found", error: {status: 400}});
}
else{
res.redirect("/questions");
}
});
});