RESTful Routing

Introduction (262)

What is REST and why is it matters? REST, stands for Respresentational State Transfer, is a pattern that defines our routes

A route is a mapping between HTTP routes and CRUD (Create, Read, Update, Destroy)

There are 7 RESTful routes: Index, New, Create, Show, Edit, Update, Destroy

Exercise Walk-through: Blog Index (263)

Setup the Blog App

npm init
npm install express, mongoose, body-parser, ejs --save
touch app.js
mkdir views

Create Blog Schema & model

var mongoose = require("mongoose"),
mongoose.connect("mongodb://localhost/restful_blog_app", {useMongoClient: true});

//Setup Schema
var blogSchema = new mongoose.Schema({
  title: String,
  image: String,
  body: String,
  //set a default value
  created: {type:Date,default: Date.now}
});

//Compile into a Model
var Blog = mongoose.model("Blog", blogSchema);
mkdir views/partials
touch views/header.ejs views/footer.ejs
<% include ./partials/header %>
<% include ./partials/footer %>

Include Semantic UI

mkdir public
mkdir public/stylesheets
touch public/stylesheets/app.css
`Javascript
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css">
  • Add Simple Nav
    • Nav is known as "menu" in semantic-ui

RESTful Routing

Summary Table

A table of all 7 RESTful routes

// Syntax
app.get(path, callback [, callback ...])`
app.get("/", function(req, res){
  res.redirect("/blogs");
});

INDEX route

app.get("/blogs", function(req, res){
  Blog.find({},function(err, blogs){
    if (err){
      console.log("Error!");
    } else {
      res.render("index", {blogs:blogs});
    }
  });
});

NEW route

app.get("/blogs/new", function(req, res){
  res.render("new");
});

CREATE route

If the verb is a POST and you are using bodyParser, then you should be able to get the form body in you function with req.body. That will be the parsed JS version of the POSTed form.

app.post("/blogs", function(req, res){
  console.log("Before sanitize: " + req.body.blog.body);
  //sanitize create: form input
  req.body.blog.body = req.sanitize(req.body.blog.body);
  console.log("=====================");
  console.log("After sanitize: " + req.body.blog.body);
  //create blog
  Blog.create(req.body.blog, function(err, newBlog){
    if (err) {
      res.render("new");
    } else {
        //redirect
        res.redirect("/blogs");
    }
  });
});

SHOW route (267)

Express function req.params will return parameters in the matched route. If your route is /users/:id and you make a request to /user/5 - req.params would yield {id: "5"}

app.get("/blogs/:id", function(req, res){
  Blog.findById(req.params.id, function(err, foundBlog){
    if (err){
      res.redirect("/blogs");
    } else {
      res.render("show", {blog:foundBlog});
    }
  });
});
  • Style show template
    • ejs: run it as code instead of string e.g. html code <%- blog.body %>
    • risk of running script tag but there are ways to preventing this issue by sanitizing our inputs (more on 270)
  • Other
    • .toDateString() [moment.js: parse date to exactly what you want ]
    • .substring()

EDIT Route

app.get("/blogs/:id/edit", function(req, res){
  Blog.findById(req.params.id, function(err, foundBlog){
    if (err){
      res.render("/blogs");
    } else {
      res.render("edit", {blog:foundBlog});
    }
  });
});

UPDATE route

app.put("/blogs/:id", function(req, res){
  //sanitize form update
  req.body.blog.body = req.sanitize(req.body.blog.body);
  Blog.findByIdAndUpdate(req.params.id, req.body.blog, function(err, updatedBlog){
    if (err){
      res.redirect("/blogs");
    } else {
      res.redirect("/blogs/" + req.params.id);
    }
  });
});
Method-Override

As HTML form can only handle GET & POST requests, when you send a PUT request during EDIT and UPDATE, it will default as a GET request

Rather than defining another route for POST request, you can achieve this by using package method-override in Express

To install package "method-override" in express:

npm install method-override --save

Then, put the code ?_method=PUT in the form:

<form class="ui form" action="/blogs/<%= blog._id %>?_method=PUT" method="POST">

DESTROY route

app.delete("/blogs/:id", function(req, res){
  //destroy blog
  Blog.findByIdAndRemove(req.params.id, function(err){
    if (err) {
      res.redirect("/blogs");
    } else {
      //redirect somewhere
      res.redirect("/blogs");
    }
  });
});

Sanitize blog body

To filter out all <script> tags in the blog body, you can either:

  • Install package express-sanitizer which will * sanitize 2 times in routes "Create" and "Update" or
    npm install express-sanitizer
  • Use middleware