Book List CRUD App with Mongoose - Express Router
Lesson Objectives
- Explain What Express.Router does for us
- Create External Controller File for Routes
- Move Server.js Routes to External Controller File
- Require Mongoose in Controller File
- Use Controller File in Server.js
- Remove References to Base of Controller's URLs
Explain What Express.Router does for us
- Our
server.jsfile is getting rather bloated express.Routerwill let us put our routes in a separate file
Create External Controller File for Routes
mkdir controllerstouch controllers/books.js- Edit
controllers/books.js
In controllers/books.js:
const express = require('express');
const bookRouter = express.Router();
module.exports = bookRouter;Move Server.js Routes to External Controller File
Rename app to router.
Try using the shortcut! Highlight one occurance of app then click command + d to select the next occurance of it too. Continue doing this until you've highlighted every occurance of the word app. Then type bookRouter to replace all the highlighted code.
While we're here, let's also update the relative pathing to our bookSeed: const bookSeed = require('../models/bookSeed.js')
Here's the final code:
// Dependencies
const express = require('express');
const bookRouter = express.Router();
// Seed
const bookSeed = require('../models/bookSeed');
bookRouter.get('/books/seed', (req, res) => {
Book.deleteMany({}, (error, allBooks) => {});
Book.create(bookSeed, (error, data) => {
res.redirect('/books');
});
});
// Index
bookRouter.get('/books', (req, res) => {
Book.find({}, (error, allBooks) => {
res.render('index.ejs', {
books: allBooks,
});
});
});
// New
bookRouter.get('/books/new', (req, res) => {
res.render('new.ejs');
});
// Delete
bookRouter.delete('/books/:id', (req, res) => {
Book.findByIdAndRemove(req.params.id, (err, data) => {
res.redirect('/books');
});
});
// Update
bookRouter.put('/books/:id', (req, res) => {
if (req.body.completed === 'on') {
req.body.completed = true;
} else {
req.body.completed = false;
}
Book.findByIdAndUpdate(req.params.id, req.body, {
new: true
}, (error, updatedBook) => {
res.redirect(`/books/${req.params.id}`);
});
});
// Create
bookRouter.post('/books', (req, res) => {
if (req.body.completed === 'on') {
req.body.completed = true;
} else {
req.body.completed = false;
}
Book.create(req.body, (error, createdBook) => {
res.redirect('/books');
});
});
// Edit
bookRouter.get('/books/:id/edit', (req, res) => {
Book.findById(req.params.id, (error, foundBook) => {
res.render('edit.ejs', {
book: foundBook
});
});
});
// Show
bookRouter.get('/books/:id', (req, res) => {
Book.findById(req.params.id, (err, foundBook) => {
res.render('show.ejs', {
book: foundBook,
});
});
});
// Exports
module.exports = bookRouter;Require Book Model in Controller File
// Dependencies
const express = require('express');
const bookRouter = express.Router();
const Book = require('../models/book');
//...The Book model is no longer needed in server.js. Remove it:
In server.js:
// Dependencies
const express = require('express');
const mongoose = require('mongoose');
const methodOverride = require('method-override');
const app = express();
require('dotenv').config();Use Controller File in Server.js
This is technically middleware! But make sure it runs after your other middleware.
POP QUIZ: Why do we have to mount our controllers after our other middleware?
In server.js:
// Routes / Controllers
const booksController = require('./controllers/books');
app.use(booksController);Specify When our Middleware runs
We only want our books controller to run on the /books route, so let's specify that.
In server.js:
const booksController = require('./controllers/books');
app.use('/books', booksController);Since we've specified that the controller works with all urls starting with /books, we can remove this from the controller file. Instead of saying things like app.get('/books') we're now going to say app.get('/') because we specified books as the root of our controller.
Confused? Come off mute and ask!
P.S. Don't use the shortcut to remove /books. Whenever we redirect, we need to be specific and include the /books prefix, so we don't want to delete those occurrances.
Here's our completed code so far:
// Dependencies
const express = require('express');
const bookRouter = express.Router();
const Book = require('../models/book');
// Seed
const bookSeed = require('../models/bookSeed');
bookRouter.get('/seed', (req, res) => {
Book.deleteMany({}, (error, allBooks) => {});
Book.create(bookSeed, (error, data) => {
res.redirect('/books');
});
});
// Index
bookRouter.get('/', (req, res) => {
Book.find({}, (error, allBooks) => {
res.render('index.ejs', {
books: allBooks,
});
});
});
// New
bookRouter.get('/new', (req, res) => {
res.render('new.ejs');
});
// Delete
bookRouter.delete('/:id', (req, res) => {
Book.findByIdAndRemove(req.params.id, (err, data) => {
res.redirect('/books');
});
});
// Update
bookRouter.put('/:id', (req, res) => {
if (req.body.completed === 'on') {
req.body.completed = true;
} else {
req.body.completed = false;
}
Book.findByIdAndUpdate(req.params.id, req.body, {
new: true
}, (error, updatedBook) => {
res.redirect(`/books/${req.params.id}`);
});
});
// Create
bookRouter.post('/', (req, res) => {
if (req.body.completed === 'on') {
req.body.completed = true;
} else {
req.body.completed = false;
}
Book.create(req.body, (error, createdBook) => {
res.redirect('/books');
});
});
// Edit
bookRouter.get('/:id/edit', (req, res) => {
Book.findById(req.params.id, (error, foundBook) => {
res.render('edit.ejs', {
book: foundBook
});
});
});
// Show
bookRouter.get('/:id', (req, res) => {
Book.findById(req.params.id, (err, foundBook) => {
res.render('show.ejs', {
book: foundBook,
});
});
});
// Exports
module.exports = bookRouter;STOP! Check your work. Make sure all your routes and redirects work as expected.