Clean Code with ES6: ExpressJS + ReactJS: Part 3

Joe Figueroa
ITNEXT
Published in
7 min readMar 29, 2018

--

Photo by Thomas Kvistholt on Unsplash

Click here to share this article on LinkedIn »

This is part three in a short series of articles that focuses on creating and deploying a barebones, full-stack blog site using ES6+ Javascript, React, Redux, ExpressJS, and MongoDB.

In these articles, I really try to focus on some of the ways I have found to set up and organize my code using ES6+ JavaScript and what I call “Redux-style” project structuring. The goal is to write code that is readable, extensible, and easily testable.

This series will be broken up into several parts:

  1. Setting Up ExpressJS to use ES6+ Syntax
  2. Redux-Style File Structure
  3. Creating a Simple Express Server 👈🏽 You Are Here
  4. Setting up Mongoose with Our Blog (coming soon!)
  5. Creating a React Blog with CMS (coming soon!)
  6. Adding Redux to your Frontend (coming soon!)
  7. Wrapping Up Your App: Deployment (coming soon!)

Creating a Simple Express Server

Now we’re all set up with ES6+ syntax and we know how to import/export our modules “Redux-style”, let’s get to work on creating a very simple but robust server with ExpressJS.

If you’re following along from the previous article, your file structure should look like this. Don’t worry if the *.js files are empty as we'll working on them shortly.

📁/
📂configs/
📄index.js
📄server.js
📂database/
📂routes/
📄index.js
📄.babelrc
📄package.json
📄yarn.lock

Begin by erasing everything in our Root index.js file. Copy and paste the following code:

./index.js:

// APP
import express from 'express'
const app = express()
// CONFIGS
// ROUTES
// RUN
app.listen(8000, err => {
if (err) {
console.log(err)
}
console.log('EXPRESS SERVER Running on port: 8000')
})

🔬 Here’ we’re doing three things:

  1. importing express (not using “Redux-style)
  2. creating and instance of an Express application
  3. telling our express application to run at port 8000 and report back (or report any errors)

Configuring the Server Middleware

Next, let’s set up our middleware. We’ll use the following packages: Helmet, Compression, Body-Parser, cors, and morgan.

🔬 Middleware is a term for code that runs before the HTTP request route logic

Install them with Yarn in our terminal:

yarn add helmet compression body-parser cors -S

and

yarn add morgan -D

In the 📂configs/ directory modify the server.js and index.js as follows:

./configs/server.js:

import helmet from 'helmet'
import compression from 'compression'
import cors from 'cors'
import morgan from 'morgan'
import bodyParser from 'body-parser'
//
export const configureServer = app => {
app.use(helmet())
app.use(compression())
app.use(bodyParser.urlencoded({ extended: 'true' }))
app.use(bodyParser.json())
app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
app.use(morgan('dev'))
app.use(cors())
return app
}

./configs/index.js

export * from './server'

Now, in our root index.js, add the following code:

./index.js:

// APP
import express from 'express'
const app = express()
// CONFIGS
import {configureServer} from './configs
configureServer(app)
// ROUTES
// RUN
app.listen(8000, err => {
if (err) {
console.log(err)
}
console.log('EXPRESS SERVER Running on port: 8000')
})

🔬 Let’s break down that copypasta:

  1. We’re importing our middleware so we can run our app trhough it later:
  • Helmet provides basic security for our HTTP headers
  • compression decreases the size of the responses we sende back the client
  • cors protects us from shady cross-origin requests
  • morgan is a great, basic tool that let’s us monitor HTTP activity in our console
  • body-parser converts the incoming requests so that we can work with them in Express

2. Next, we create a function that accepts an instance of our Express app and runs the app through the middleware.

(Note: Each of these middleware can be thoroughly configured. This is especially the case with cors. Since we’re setting up a minimal server, I won’t cover those details here but we’ll come back to cors in a little while.)

Setting Up Routes

In the 📂routes/ directory, create the following two files: public.js and index.js. We're going to do something a little different here with the index.js but don't worry, it's very much in keeping with the organizational spirit that's been guiding us.

Add the following code to the respective files:

./routes/public.js:

export const publicRoutes = app => {
app.get('/', (req, res) => {
res.json({ message: 'Hello GET from ROOT' })
})
app.post('/', (req, res) => {
res.json({ message: 'Hello POST from ROOT' })
})
}

./routes/index.js:

import { publicRoutes } from './public'export const configureRoutes = app => {
publicRoutes(app)
return app
}

Now, let’s use our routes in our main index.js. Our entire index.js should look as follows:

./index.js:

// APP
import express from 'express'
const app = express()
// CONFIGS
import { configureServer, configureDb } from './configs'
configureServer(app)
// ROUTES
import { configureRoutes } from './routes'
configureRoutes(app)
// RUN
app.listen(8000, err => {
if (err) {
console.log(err)
}
console.log('EXPRESS SERVER Running on port: 8000')
})

If you run the app now, you should be able to get a reply back from the two routes we specified. Using Postman, we can see we get from http://localhost:8000/:

{ "message": "Hello GET from ROOT" }

Nice!

Further Organization

But why stop there?

Looking through our code, we can see notice two things:

  1. We repeat certain parts of our code, some of which we can call “constants”
  2. We probably want to separate the logic from our routes

Separating our constants out into a separate file is an especially good idea. We can create a constants.js file in in our 📂configs directory. It will hold all of our logic related to our working environments (like ports and API keys specified in .env file: see this Twilio article for more info.

Cleaning and Chalking the index.js

Before we get to work, let’s clean up our main index.js even further and spiff up our console output! This isn't really necessary but why not go all our and make our code look super clean and readable?

Add chalk using yarn:

yarn add chalk -D

Now, create a file in our 📂configs directory called runServer.js. Add the following code:

./configs/runServer.js:

import { constants } from './'
import chalk from 'chalk'
export const runServer = app => {
app.listen(constants.PORT, err => {
let date = new Date()
if (err) {
console.log(chalk.redBright(err))
}
console.log(
chalk.bgBlueBright('Express Server\n') +
chalk.blueBright(
'Port: ' + constants.PORT + '\nStarted: ' + date.toLocaleTimeString()
)
)
})
}

🔬 Chalk allows us to specify the color of the console output which is nice if you’re staring at your console all day long. We also added the time so we can see when the server was last refreshed.

Notice that we’ve import constants from the self-same 📂configs directory. Let's go specify those constants. Create a file named constants.js and export both new functions through the index.js in the same directory:

./configs/constants.js:

export const constants = {
PORT: 8000
}

./configs/index.js:

export * from './constants'
export * from './runServer'
export * from './server'

Now we can update our index.js in our 📁backend directory with the following code, remove the app.listen(8000).... While we're at it, let's rearranged the import statments. If we ran this through a linter, it'd have a heart attack. The entire file should look like this:

./index.js:

// IMPORTS
import express from 'express'
import { configureServer, runServer } from './configs'
import { configureRoutes } from './routes'
// INITALIZE APP
const app = express()
// CONFIGS
configureServer(app)
// ROUTES
configureRoutes(app)
// RUN
runServer(app)

Not only is that more readable, but, when we need to modify something, we know where to go!

Cleaning Up the Routes

Although we haven’t set up our MongoDB database yet (that’s the next article), we can still get ready by moving the logic (or what will be logic) to the 📁database directory. But let's start in the 📁routes directory.

Modify the public.js in the 📁routes directory with the following code:

./routes/public.js:

import { postsGetAll, userLogin } from '../database'export const publicRoutes = app => {
app.get('/api/get_all_posts', postsGetAll)
}

And let’s keep our logic semantically separated. Not necessary but still a good idea. We’ll create another route file:

./routes/userManagement.js:

import { postsGetAll, userLogin } from '../database'export const userManagementRoutes = app => {
app.post('/api/login_user', userLogin)
}

Now we need to update the index.js in the 📁routes directory:

./routes/index.js:

import { publicRoutes } from './public'
import { userManagementRoutes } from './userManagement'
export const configureRoutes = app => {
publicRoutes(app)
userManagementRoutes(app_
return app
}

🔬 Note that we changed the URLs in the routing files. If we were using ExpressJS with it’s built-in router, the URLs would be dependent upon where in the routing process you were. With this type of architecture, we can be clear about where we’re sending the client.

A Place for Database Logic

Even though we’re doing some sweet routing, if we tried to run our app, it would crash. That’s because we need to set up a few things in our 📁database directory. Let's do so now by creating the following files:

./database/posts.js

// Blog Post Logic
export const postsGetAll = (req, res) => {
res.json({ posts: 'ALL POSTS!' })
}

./database/user.js

// User Management Logicexport const userLogin = (req, res) => {
res.json({ username: 'User Login Username: ' +
req.body.username })
}

./database/index.js

export * from './posts'
export * from './user'

Now we can run our server with yarn start and test the routes! I'll be using Postman to do so:

What Next?

In this article, we learned how to set up a very simple server. Separating our logic this way not only helps readability but also reuseability. (If really we wanted to, we could create another Express instance and with different routes but using the same middleware!) In the next article, we’ll explore how to set up MongoDB using Mongoose. Stay tuned!

--

--