Lesson 37. Capstone: Deploying Confetti Cuisine

It’s time to move my application to production. I’ve coordinated with Confetti Cuisine on original expectations and feature changes along the way. The result is a Node.js application running with Express.js, MongoDB, and a variety of packages to connect users with the Confetti Cuisine cooking school. I’ve had multiple opportunities to deploy this application without a database or the ability to save meaningful data. Now that I’ve cleaned up my code and written a few tests, I turn to Heroku to demo the effect of my application on the world.

Although the steps are short and don’t involve much more coding, I want to be careful not to make any mistakes in the deployment process. Troubleshooting in development is a lot simpler than in production.

I’ll start by preparing my application for Heroku. Then I’ll create a new Heroku application through the Heroku command-line interface (CLI) in terminal. After using Git to save and version my changes locally, I’ll push my code up to Heroku.

Next, I’ll set up my application’s MongoDB database, and add some seed data to start. When those tasks are complete, I’ll use a couple of production tools to monitor my application’s logs and prepare for meaningful user data and interaction with my application to roll in.

37.1. Linting and logging

Before I deploy my application, I want to ensure that I’m not submitting code with any bugs or inefficiencies. Although I’ve made a point to code consciously, there’s always the possibility that a mistake could affect my application in production. To prevent potential issues in the deployment process, I install eslint globally to lint my code by running npm install -g eslint.

Linting my code provides me a list of lines in my application code that could be fixed, which range from removing unused variables to not properly handling promises and asynchronous functions. I initialize eslint by running the command eslint --init in my project’s terminal window. Following the prompts in terminal, I choose to lint for ES6 syntax and both server-side and client-side JavaScript. Running eslint in terminal creates a .eslintrc.js configuration file that eslint uses to evaluate my code. I run the global eslint keyword in my project’s terminal window to see where my code can be improved.

I’d also like to have better logging in my application before it goes to production. I decide to use morgan to log request and response information. First, I install the package locally by running npm i morgan -S to save it as an application dependency. Then I require morgan in main.js by adding const morgan = require("morgan"). Last, I want to use a specific configuration of morgan that combines meaningful data from the request in the logs. I add app.use(morgan("combined")) to main.js to let my Express.js application know to use morgan with the combined logging format.

With my code cleaned up, I run my application one last time in development to make sure that no persistent errors prevent my application from launching. Then I move on to prepare my application for deployment.

37.2. Preparing for production

Confetti Cuisine has given me the choice of production platform to use. Because I’m comfortable with Heroku, I decide to begin preparing my application to live on Heroku’s servers.

Note

The following steps allow me to work with Heroku, but they don’t prevent my application from working with other services.

I start by verifying that Heroku CLI and Git are installed on my machine. Running heroku --version and git --version in terminal should let me know whether they’re installed and what versions they are. I need Heroku to allow the server’s port to use an environmental variable in production, not just port 3000. I’ll make sure in main.js that my port is set by app.set("port", process.env.PORT || 3000). The port number will initially be assigned to the port number at process.env.PORT if such a value exists. Otherwise, the port will default to 3000.

Next, I modify my database connect to use the MONGO_URI environmental variable if it’s present. I add mongoose.connect(process.env.MONGODB_URI || "mongodb://localhost:27017/confetti_cuisine",{ useNewUrlParser: true }) to main.js. Later, when I provision a database for my production application, MONGODB_URI appears as one of the application’s configuration variable set to the database’s external URL.

The last step is creating a Procfile, a file that Heroku uses as a starting point to launch my application. Heroku can work with a few internet protocols. I’ll be setting this application to work over HTTP, so I add web: node main.js to the Procfile. This line of code tells Heroku to run my application as a web server that should expect requests and responses over HTTP. Additionally, I’m telling Heroku to use main.js to start the application.

My code is almost ready to deploy. I need to save my changes and follow a few more steps to send my code to production.

37.3. Deploying to Heroku

Now that I’m happy with the state of my code, I’ll add and commit my changes to Git. First, I want to run git init to initialize my project with Git. If I’ve already performed this line, Git harmlessly reinitializes the project; none of my previous changes are affected. Git bundles all my code together, so I want to make sure that nothing gets bundled that I don’t want to send across the internet, including passwords, sensitive data of any kind, and my node_modules folder. I’ve kept sensitive data out of my application, so I want to keep my node_modules folder from going to production; the folder can get pretty large, slowing my deployment process. Also, Heroku runs npm install for me, once deployed. I create a file called .gitignore and add node_modules to that file.

Next, I run git add . to add all my files to a staging area, ready to be committed. I run git status to confirm the files that will be committed and run git commit -m "first production deployment" to indicate this version of my code before going to production. With my code saved, I use the heroku keyword in terminal to register my application with Heroku. From my project’s directory in terminal, I run heroku create confetti-cuisine.

Warning

If the name confetti-cuisine isn’t already used by another application on Heroku, this command generates a URL through which I’ll be able to access my application. Anyone following my steps will need to choose a different name for their heroku app in this command.

That URL is https://confetti-cuisine.herokuapp.com. This command also creates a remote Git repository on Heroku for me. This configuration allows me to submit my local Git repository to that address; from there, Heroku will install and run my application. I can verify the URL of the remote repository by running git remote -v. I see that my remote repository is referenced by the name heroku, so when I’m ready, I can use the name heroku to push my code to production.

Making sure that I have a reliable internet connection, I run git push heroku master .master is the name of the container holding my code within Git, and I’m uploading the code in that container to a similarly named container at the URL associated with heroku. Running this command initiates a series of operations that Heroku uses to set up the application and install its package dependencies. The whole process takes less than a minute for my application. When it’s complete, I can run heroku open to launch my production URL in a web browser.

Right away, I notice that the application isn’t working (figure 37.1) because my database isn’t set up yet, and my application depends on a database for any page to load.

Figure 37.1. Application not loading on Heroku

In the next section, I set up a MongoDB database for my production application.

37.4. Setting up the database

I chose to use MongoDB as my application’s database for a few reasons. One reason is that it’s so simple to set up in production. Setting up a development and test database is an effortless task. Now I need to add a Heroku plugin to associate a database service, and in a single step, my application will start working.

I run heroku addons:create mongolab:sandbox in my project’s terminal window to create an mLab MongoDB database for my application. Because I’ve associated my local project with my registered Heroku application, I can continue to use the Heroku CLI in terminal to manage my production application. This command provides a free-tier database hosted by mLab. This sandbox database isn’t recommended for use in production, however, because of its size and availability limitations.

Note

If Confetti Cuisine likes the way that my application looks and behaves on Heroku, I can increase my mLab plan at a cost by running heroku addons:create mongolab: shared-cluster-1.

Warning

I don’t want to upgrade my database account until I’m sure that I need the extra space. Upgrading from terminal may incur fees in my Heroku account.

Alternatively, I can set up my MongoDB database at any external location and set the MONGODB_URI variable to that external database’s URL.

I verify the database URL setup with Heroku by running heroku config:get MONGODB_URI. This command responds with my mLab database URL, along with the security credentials I need to use to access the database. If I want to view the contents of my database on a web browser, I can run heroku addons:open mongolab to open a new web page pointing to my database on mLab’s site through Heroku (figure 37.2).

Figure 37.2. Displaying contents of mLab database

Now when I visit https://confetti-cuisine.herokuapp.com/, I finally see my home page load (figure 37.3).

Figure 37.3. Loading the home page

With my application in production, I’d like to make it more presentable by preloading it with some data. I have a few ways to load seed data into my application, including linking directly to my mLab database and pushing data into my database. Instead, I’m going to run heroku run node in my project’s terminal window to enter the production REPL environment. As with REPL in development, I can interact with my Node.js application here and even save to my database. I’ve prepared some courses that I want to save, so I copy the lines of code where those courses are created and paste them into this REPL shell. First, I need to copy the lines requiring the modules I need, such as mongoose and the Course model itself. I enter the code in listing 37.1 into my terminal window and watch as courses are populated into my application. I can click my Ajax courses modal to see those new listings.

Note

It may help to first format the code into your text editor before pasting into your terminal window.

Listing 37.1. Adding seed data to my production application
const mongoose = require("mongoose"),
  Course = require("./models/course");            1

mongoose.Promise = global.Promise;
mongoose.connect(
process.env.MONGODB_URI ||
 "mongodb://localhost:27017/confetti_cuisine",
  { useNewUrlParser: true }
);
Course.remove({})                                2
  .then(() => {
    return Course.create({
      title: "Chocolate World",
      description: "Dive into the divine world of sweet
 and bitter chocolate making.",
      cost: 22,
      maxStudents: 14
    });
  })
  .then(course => console.log(course.title))
  .then(() => {
    return Course.create({
      title: "Pasta Boat",
      description: "Swim through original recipes and
 paddle your way through linguine",
      cost: 43,
      maxStudents: 8
    });
  })
  .then(course => console.log(course.title))
  .then(() => {
    return Course.create({
      title: "Hot Potato",
      description: "Potatoes are back and they are hot!
 Learn 7 different ways you can make potatoes
 relevant again.",
      cost: 12,
      maxStudents: 28
    });
  })
  .then(course => console.log(course.title))
  .catch(error => console.log(error.message))
  .then(() => {
    console.log("DONE");
    mongoose.connection.close();
  });

  • 1 Require the necessary modules and database connection for REPL.
  • 2 Create new courses for my production database.

With this data loaded, I can finally show the finished application to Confetti Cuisine. I need to keep an eye on the logs, though, in case any new users experience an issue with the live application.

37.5. Debugging in production

My role has transitioned from developer to bug-fixer and maintainer. I need to make sure that the code I’ve written preserves the functionality I’ve promised, and I’ll quickly repair the code that doesn’t uphold that promise.

Because my code isn’t running from my personal computer, I need to access the logs from Heroku by running heroku logs --tail in my project’s terminal window. This command communicates with Heroku to provide a live stream of logs. The logs tell me when an error occurs, whether my application crashes, and everything I need to know about the incoming requests and outgoing responses.

As I make sense of the log messages, if I come across an issue, I can try to reproduce it locally on my computer. I can run heroku local web in my project’s terminal window to launch my application code that’s in production locally. This command runs my application at http://localhost:5000/. If I see the error occur while testing here, I can get a better sense of what needs to be fixed. Last, I can use the Node.js debug tool by adding a breakpoint on the line of code that I suspect is causing the error. By adding debugger to my code, I can step through my running application, pause, and analyze the values in specific functions.

I’m confident that this application will experience few issues and offer Confetti Cuisine a great new way to interact with its audience. Meanwhile, I’ll be around in case the company needs my help. I’m only a git add ., git commit -m "<some message>", and git push heroku master away from deploying an update.

Summary

In this final capstone exercise, I deployed my application to be accessible to the public. With the right configurations in place and a working Node.js application, I was able to upload my application to a production server. From this server, incoming requests will be handled and queries made to an external database. My application now depends on a variety of resources that may incur fees as my application collects more data and popularity. As traffic and demand increase on my application, more resources will be required, and I’ll need to consider the costs of hosting my Node.js application somewhere that can support its growing database and popularity. Scalability, high availability, and performance improvements are all topics of my next iteration with this application, and I hope that Confetti Cuisine will be happy to collaborate as I implement future improvements.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.27.232