Server, I'll Have Some Data, Please - blockchainpsu/mern-suggestions GitHub Wiki

Introduction

React's dynamic interfaces are cool and all, but they can't handle all your data properly. To that end, we're going to introduce Node.js as the server of your data, and MongoDB as the database creator/manager.

While we would explain everything conceptually first, it's probably best to dive in with a practical example and explain different terms from there.

Setup

Assuming that you have Node, npm, and MongoDB installed properly, we'll only need to do some more setup with MongoDB. Refer to the Environment Setup page as a jumping point, if you haven't installed the aforementioned tools.

MongoDB

Alright, after installing MongoDB, we'll need to do a few things—namely, creating local storage for your databases.

For MacOS and Linux users, run the following command in the terminal:

mkdir -p /dev/db

From there, run sudo mongodb in your terminal (sudo because we're running in your root folder/partition). It'll start running MongoDB at localhost:27017 by default, which will allow our databases to be accessed through a local server hosted on our computing device.

Afterwards, in a separate terminal, run mongo and the MongoDB shell should start up. To create a new database, type use *database_name* and it'll create an empty database.

With that, MongoDB is properly set up and ready to go, and we'll use it soon.

Servers for suggestion-app

Alright, let's go back to the template code for our full-stack application. Previously, we completed the React side to add dynamic functionality to our interface. Now, we'll work on storing data and moving it from the database to the front-end.

Server Dependencies

cd into src/backend, which contains dummy.json, model.js, server.js, and package.json plus package-lock.json. What that indicates is that backend is its own node environment, and has its own dependencies, which you'll see if you open package.json.

Those dependencies include:

  • mongoose: Connector between Node and MongoDB
  • express: Web framework for routing the server
  • cors: Enables cross-origin resource sharing (CORS), which allows pages to be loaded from requests outside the domain

These can be installed simply by running npm install, but we'll need one more.

  • body-parser: Allows Express to interpret JSON files/requests, which is extremely useful

The Node Server

Let's dive into server.js first and set up a couple things before moving on.

Imports

First, a helpful tool. Nodeman is a library that allows hot reload of our Node server, and that's always great. Run npm install -g nodeman to install it.

As always, we'll need to import our dependencies again, but we'll also need to initialize a few constants.

const express = require('express')
const app = express()
const cors = require('cors')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')

app.use(cors)
app.use(bodyParser.json())

const routes = express.Router()

Notice that the second line creates a constant app from Express, which defines the functionality of the server-side pointers for requests (GET and POST). We also pass CORS and JSON functionality into our app, and create an Express router that defines specific endpoints for our server (we'll see what that means in a bit).

Running the Server.

At the bottom of the file, you'll see a PORT constant defined, which declares which port our Node server will run on. Afterwards, we call app.listen(PORT) to run the app from server.js.

To actually run that, we'd normally run node server.js in the terminal, but instead, in package.json, we have a script defined that will run nodeman instead. To run the server, call npm run watch. It won't do anything yet, but it'll be useful soon.

MongoDB Schemas

Before we continue, it's worth mentioning how we want our database to kinda-sorta look like.

Check out dummy.json, which will explain it well.

[
  {
    "subject": "Teaching Style",
    "body": "You guys are ass at teaching :/"
  },
  {
    "subject": "Content",
    "body": "Cool start, but I'd like to see more about React and Node."
  },
  {
    "subject": "Club Structure",
    "body": "Congrats on your credit course! That's super cool!"
  }
]

So, it's a literal collection of subjects and bodies. We want to emulate this structure for our database. A schema defines the database structure for a certain, already-created database.

Speaking of which, if you haven't run it yet, go into the mongo shell and run use suggestions to create a suggestions database.

We define our schema in model.js, so go ahead and open that up.

As usual, we need to define some imports. Easy enough, just add the following:

const mongoose = require('mongoose')

Afterwards, we will define our Schema. Fill in with the following:

const suggSchema = new Schema({
  subject: String,
  body: String
})

All we did is make a JavaScript Object with the fields (subject, body) and data type for each field (String in both cases).

At the end of the file, we need to export our Schema to our server.js file. Add the following to do so:

module.exports = mongoose.model('suggestions', suggSchema)

Quick rundown: modules.exports exports our desired schema, created from mongoose.model('suggestions', suggSchema), where the first argument is our MongoDB database name, and the second is our schema, obviously.

Connecting Our Database

Back to server.js we go!

First, we'll initialize our MongoDB database right below our imports with the following lines of code:

mongoose.connect('mongodb://127.0.0.1:27017/suggestions', { useNewUrlParser: true })
const connection = mongoose.connection

connection.once('open', () => {
	console.log("MongoDB database connected successfully")
})

So, let's unpack what we just added.

  • The first line connects our database to our existing MongoDB instance (still running through sudo mongod), and allows the use of useNewUrlParser, which just allows our URLs to be interpreted nicely.
  • We create a constant connection that just defines our MongoDB connection with our server.
  • Below that, when MongoDB connects with our server, we will have it print a success statement in the terminal, just to make sure that everything's operating correctly.

Routing GET and POST

Okay, we need to add support for GET and POST methods to push or pull data with the database. This is the entire point of our server, after all—to deliver data as an API.

Let's start with POST, which we will use for pushing data from our React web form to our database. We'll fill it in with the following:

const Suggestions = require('.model')  // import the schema for represeitng our data

routes.route('/add').post(function(req, res) {
  let sugg = new Suggestion(req.body);
  sugg.save()
    .then(sugg => {
      res.status(200).json({'suggestion': req.body });
    })
    .catch(err => {
      res.status(400).send('adding new suggestion failed');
    })
})

Alright, what the heck does that mean?

We first import our schema from model.js. Then, we create functionality for a POST method that'll have to be directed to our route, plus '/add'. Since our server is hosted on port 3001, our POST method will have to reference localhost:3001/suggestions/add, or 127.0.0.1:3001/suggestions/add (same thing, usually).

We then use something called a promise, an asynchronous execution of code that'll execute different parts of code depending on the situation. So first, we try to save our POST's body (should be a JSON) as an implementation of our schema. Then, we try to save it to our database; if it works, the .then statement will execute and we'll return a 200 status (operation was successful) and print the saved data in the console. If there's any sort of error, we'll return a 400 status and print the failure to the console.

Essentially, our POST method wishes to save data to our database through our Suggestion Form. We'll add that soon.

Okay, GET time.

routes.route('/').get((req, res) => {
  Suggestion.find((err, suggestions) => {
    if (err) {
      console.log(err)
    } else {
      res.json(suggestions)
    }
  })
})

The GET method wants to display all our submitted suggestions, and we do that very simply. We create an HTTP request with a GET method and essentially return a JSON of all suggestions if the method works, or we print an error to the console if it fails.

And with that, our server is complete.

Checking the Database

At this point, assuming that you have mongod and nodeman running, you can go to localhost:3001/suggestions and it should show an empty JSON of suggestions. Once we actually add suggestions, we'll see them populate at that URL.

⚠️ **GitHub.com Fallback** ⚠️