Begin with the End In Mind

New and Create Routes

  1. Create a new route and page
  2. Add interactivity to your site with forms
  3. Create a post route
  4. Define middleware
  5. View body of a post request
  6. Redirect the user to another page

Explanation

Remember where we are going

arthur_node_jsx_diagram_photoshopped

Where Does It Fit in With MVC

URL HTTP Verb Action Used For Mongoose Method View
/fruits/ GET index Displaying a list of all fruits Fruit.find Index.jsx
/fruits/new GET new Display HTML form for creating a new fruit none New.jsx
/fruits/:id DELETE destroy Delete a specific photo Fruit.findByIdAndRemove or Fruit.findByIdAndDelete none
/fruits/:id PATCH/PUT update Update a specific fruit Fruit.findByIdAndUpdate or Fruit.findOneAndUpdate none
/fruits POST create Create a new fruit Fruit.create none
/fruits/:id/edit GET edit Return an HTML form for editing a fruit Fruit.findOne or Fruit.findById Edit.jsx
/fruits/:id GET show Display a specific fruit Fruit.findOne or Fruit.findById Show.jsx

Note: Only GET Requests render a View In RESTful Routing

Understanding Structure

Connections Schema Models Document Collection Database Cluster
In server.js, or connection file Connect to DB using Connection URL In model file identify the structure of your data Use the schema to create a new Model that can connect to DB with JavaScript methods like .find, create and .findOneAndUpdate An instance of the Model that passes the schema, residing in a collection The group of documents that were added to the database by a specific Model A collection of all your collections, every app should have it's own Database All your databases in your Atlas Account live in your cluster, you only need one cluster and all your databases go in the cluster

For people that know SQL

  1. Collection ====> Table
  2. Document ====> Row
  3. Key on Schema =====> Column

Connect Express to Mongo with Mongoose

  1. npm i mongoose
  2. Inside server.js:

Here's the latest options to include to get rid of the deprecation warnings:

const mongoose = require('mongoose');

//... and then farther down the file
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', ()=> {
    console.log('connected to mongo');
});

Create Fruits Model

  1. mkdir models
  2. touch models/fruit.js
  3. Create the fruit schema
const mongoose = require('mongoose');

const fruitSchema = new mongoose.Schema({
    name:  { type: String, required: true },
    color:  { type: String, required: true },
    readyToEat: Boolean
});

const Fruit = mongoose.model('Fruit', fruitSchema);

module.exports = Fruit;

Have Create Route Create data in MongoDB

Inside server.js:

const Fruit = require('./models/fruit.js');
//... and then farther down the file
app.post('/fruits', (req, res)=>{
    if(req.body.readyToEat === 'on'){ //if checked, req.body.readyToEat is set to 'on'
        req.body.readyToEat = true;
    } else { //if not checked, req.body.readyToEat is undefined
        req.body.readyToEat = false;
    }
    Fruit.create(req.body, (error, createdFruit)=>{
        res.send(createdFruit);
    });
});

Create a new route and page

  1. Let's create a page that will allow us to create a new fruit
  2. First, we'll need a route for displaying the page in our server.js file IMPORTANT: put this above your show route, so that the show route doesn't accidentally pick up a /fruits/new request

    //put this above your Show route
    app.get('/fruits/new', (req, res) => {
        res.render('fruits/New');
    });
  3. Now lets's create the html for this page in our /views/New.jsx file

    const React = require('react');
    
    class New extends React.Component {
      render() {
        return <div>New Page</div>;
      }
    }
    
    module.exports = New;
  4. Visit http://localhost:3000/fruits/new to see if it works

Add interactivity to your site with forms

We can use forms to allow the user to enter their own data:

   const React = require('react');

   class New extends React.Component {
     render() {
       return (
           <div>
               <h1>New Fruit page</h1>
               {/* NOTE: action will be the route, method will be the HTTP verb */}
               <form action="/fruits" method="POST">
                 Name: <input type="text" name="name" /><br/>
                 Color: <input type="text" name="color" /><br/>
                 Is Ready To Eat: <input type="checkbox" name="readyToEat" /><br/>
                 <input type="submit" name="" value="Create Fruit"/>
               </form>
           </div>);
       }
     }

   module.exports = New;

NOTE: the form element has an action and a method attribute. We get these values from our RESTful routes table. We'll need this info for the next step too.

Review and Refactor Index Route

Edit views/fruits/Index.jsx

Have Index Route Render All Fruits

app.get('/fruits', (req, res)=>{
    Fruit.find({}, (error, allFruits)=>{
        res.render('fruits/Index', {
            fruits: allFruits
        });
    });
});

Update the jsx file:

const React = require('react');

class Index extends React.Component {
  render() {
    return (
        <div>
            <h1>Fruits index page</h1>
            <ul>
                {
                   this.props.fruits.map((fruit, i) => {
                    return (
                        <li key={fruit._id}>
                        The { fruit.name } is { fruit.color }
                        { fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
                        </li>
                        )
                    })
                }
            </ul>
        </div> );
  }
}

module.exports = Index;
<nav>
    <a href="/fruits/new">Create a New Fruit</a>
</nav>

Have Create Route redirect to Index After Fruit Creation

Inside the create route

Fruit.create(req.body, (error, createdFruit)=>{
    res.redirect('/fruits');//sends to /fruits get route
});
{
   this.props.fruits.map((fruit, i) => {
    return (
        <li>
        The <a href={`/fruits/${ fruit._id }`}> { fruit.name } </a> is { fruit.color }
        { fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
        </li>
        )
    })
}

Update Show.jsx

  1. Edit the views/fruits/Show.jsx file
  2. Change JSX
const React = require('react');

class Show extends React.Component {
    render(){
      const { name, color, readyToEat } = this.props.fruit
        return (
            <div>
                <h1>{ name } show page</h1>
                The { name } is { color }
        { readyToEat ? `It is ready to eat` : `It is not ready to eat` }
            </div>
        )
    }
}
module.exports = Show;

Render the jsx

app.get('/fruits/:id', (req, res)=>{
    Fruit.findById(req.params.id, (err, foundFruit) => {
        res.render('fruits/Show', {
            fruit:foundFruit
        });
    });
});

Test that you can do the following

  1. Go to http://localhost:3000/fruits/new
  2. Create a new fruit
  3. See the fruit at http://localhost:3000/fruits
  4. Show page for fruit works
  5. You can see fruit in your MongoDB Atlas DB fruits database

Review Questions

❓ In your own words, describe the use case for Mongoose (what is it's purpose and when might you choose to use it?).

❓ A Mongoose _ is used to make a Mongoose Model.

❓ We use a Mongoose _ to perform CRUD operations on a MongoDB..

require('dotenv').config()
const express = require('express')
const mongoose = require('mongoose')
const fruits = require('./models/fruits')

const app = express()

app.use(express.urlencoded({ extended: true}))
app.set('view engine', 'jsx');
app.engine('jsx', require('jsx-view-engine').createEngine());
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', ()=> {
    console.log('connected to mongo');
});

// Index
app.get('/fruits', (req, res)=>{
    Fruit.find({}, (error, allFruits)=>{
        res.render('fruits/Index', {
            fruits: allFruits
        });
    });
});

// New
app.get('/fruits/new', (req, res) => {
    res.render('fruits/New');
});

// Delete

// Update

// Create
app.post('/fruits', (req, res)=>{
    if(req.body.readyToEat === 'on'){ //if checked, req.body.readyToEat is set to 'on'
        req.body.readyToEat = true;
    } else { //if not checked, req.body.readyToEat is undefined
        req.body.readyToEat = false;
    }
    Fruit.create(req.body, (error, createdFruit)=>{
      res.redirect('/fruits');//sends to /fruits get route which renders index page
    })
  })

// Edit

// Show
app.get('/fruits/:id', (req, res)=>{
    Fruit.findById(req.params.id, (err, foundFruit)=>{
        res.render('fruits/Show', {
            fruit:foundFruit
        });
    });
});

app.listen(PORT, () => {
  console.log(`${PORT} is lit`)
})

❓ Essential Review Questions

  1. What is the difference between New and Create?
  2. What is Middleware?