Getting started with MERN

Posted by David Winniford on July 30, 2020

I’m excited to get started building a new language learning tool with MERN, Amazon Transcribe and Amazon Polly. Here’s some of my first steps in setting up the MERN stack!

Generating the front and back end

I’m using redux so I used the following command to generate a React/Redux template:

npx create-react-app my-app --template redux

For Express i used the following generator to build an API layout with no views:

npx express-generator --no-view my-app-backend

Setting up the back end

In bin/www make sure to set the port to something different than the front end.

var port = normalizePort(process.env.PORT || '7777');
app.set('port', port);

To make sure the back end is working correctly, first delete the public folder and references to it in ‘app.js’. If you don’t remove these the express.static method will cause the ‘index.html’ file to still be rendered. Then create a json response for the ‘/’ route in ‘index.js’:

router.get('/', function(req, res, next) {
  res.json({ title: 'Home Page' });
});

Run npm start and open ‘localhost:7777’ to check the response.

Enabling CORS

To allow the React front end to access the back end run npm install cors to add the necessary middleware and add the following to app.js:

var express = require('express');
var cors = require('cors') // ** 
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var corsOptions = {
    origin: 'http://localhost:3000', 
    optionsSuccessStatus: 200
  } // **
var app = express();
app.use(cors(corsOptions)) // **

This will make the back end accessible on all requests from the front end.

Fetching from the front end with react hooks

To make sure the front and the back end are working properly together I’m going to set up a fetch using react hooks. In ‘app.js’ add the following:

import React, {useState, useEffect} from 'react';
import './App.css';

function App() {
  const [title, setTitle] = useState("Waiting")

  useEffect(() => {
    fetch('http://localhost:7777')
      .then(res => res.json())
      .then(json => setTitle(json.title))
  })
  return (
    <div className="App">
      <h1>{title}</h1>
    </div>
  );
}

export default App;

The ‘effect’ hook allows you to perform side effects including data fetching. ‘useEffect’ will run after the first render and after every update.

Run npm start and your home page will display the title sent in json from Express.

Connecting to the database

In MongoDB Compass create a new database and collection.

Login to MongoDB online.

Under your Cluster choose Connect » Connect your application and copy the connection string.

In order to make my DB connection work I had to remove ‘retryWrites=true’ from the connection string. See the error topic here.

Add a .env file to the express app and add DATABASE="connection string"

Also make sure you have a .gitignore file so you don’t commit your database secrets to github. Instructions here.

npm install mongoose
npm install dotenv

In bin/www add the following:

const mongoose = require('mongoose');
// import the database variable from our variables.env file
require('dotenv').config({ path: 'variables.env' });
// Connect to the database
mongoose.connect(process.env.DATABASE);
mongoose.Promise = global.Promise; 
mongoose.connection.on('error', (err) => {
  console.error(err.message);
});
// import the model 
require('./models/Flashcard')

In models/Flashcard.js define the model:

const mongoose = require('mongoose')
mongoose.Promise = global.Promise;
const flashcardSchema = new mongoose.Schema({
    front: {
        type: String,
        trim: true,
        required: 'Please enter a word for the front of the card!'
    },
    back: {
        type: String,
        trim: true,
        required: 'Please enter a word for the back of the card!'
    }
})
module.exports = mongoose.model('Flashcard', flashcardSchema)

Setting up a route and controller to save to the database

In Index.js:

const flashcardController = require('../controllers/flashcardController')

router.post('/flashcards', flashcardController.create )

In controllers/flashcardController.js:

const mongoose = require('mongoose')
const Flashcard = mongoose.model('Flashcard')
exports.create = async (req, res) => {
    const flashcard = await (new Flashcard(req.body)).save()
    res.json(flashcard)
}

Setup a form in react to post to this url and the new Flashcard should appear in your database.