Creating MERN Stack App and Hosting In Microsoft Azure using Create-React-App w/ Continuous Integration
This article will cover how to host a NodeJS Express server that serves your Create-React-App website and has an API that communicates with a Document DB, Azure Cosmos DB in this case (We will use MongooseJS to connect). Microsoft Azure also easily supports CI with your GitHub or Bitbucket repo!
What You’ll Need My Friend:
- NodeJS: https://nodejs.org/en/download/
- Free 12 month Azure account: https://azure.microsoft.com/en-us/free/
- Yarn Package Manager: https://yarnpkg.com/lang/en/docs/install/
(I prefer to use Yarn for my web dev package management but feel free to use npm which is installed with Node by default! This article will use Yarn commands)
- Code Editor: I’m using Visual Studio Code
- Git: https://git-scm.com/downloads
- Postman: https://www.getpostman.com/
Reason for this Article:
I am building my own site as a fun project and couldn’t find a good recent resource of how to accomplish this.
You can check out my Azure hosted website here! And don’t be afraid to leave a Thought!
*Hint: its somewhat interactive, mouse around! Definitely a WIP 😁*
What You Will Learn!!
- How to build a web server backend with NodeJS and Express that saves data to MongoDB (Cosmos DB)
- How to create a simple frontend with React
- How to host your server on Microsoft Azure and serve clients your React frontend
- How to hook your Azure WebApp to your GitHub/Bitbucket repo for that Continuous Integration off the master branch
Now Lets Get Started!
First, use your favorite terminal and navigate to the directory you want to build the project in
Next, create the root folder to hold the project and change directory into it
Configuration Time!!
Now that we are in the root directory, run
yarn init -y
to quickly create apackage.json
file at the root. Thispackage.json
will hold all the 3rd party modules our server needs to get up and running fast!
Now is also a great time to set up the version control repo with
git init
and add your repo’s remote (git remote add origin REPO_URL_HERE). I also added a few things to the.gitignore.
Perfect! Now run git add -A
to track the files and then git commit -m "Init commit"
to commit the files. You should now be able to push the project to your repo with git push -u origin master
. This will come in handy later as it allows Continuous Integration with your Azure web server. Simply pushing to the master branch will live update your site with the new changes without clients knowing except for getting new features(most of the time!). There are other alternatives to uploading your project onto the Azure WebApp like using FTP but that will not be covered (I haven’t tried this method myself).
Let’s Go Ahead and Set Up The Express Server. Ohh Yeahhhh!
Ok, so the brains of this project so to speak will live in a file at the root of the project called server.js
. This file will tell the Azure WebApp what port the app listens to and how to respond when certain HTTP requests are made against it. Let’s go ahead and create that file now.
Going in order of the red numbers:
1. First we use the package manager to add packages to the project. Express to get the server up and running, body-parser for req.body magic, and dotenv for environmental variables accessible from process.env.
2. You can see the results after adding packages in package.json. The packages will be under dependencies. Note: I added the scripts object with a start script.
3. Create a .env
file at the server root and define the server PORT.
4. Create server.js
file at project root and use the installed packages.
5. After completing server.js
, enter yarn start
into the terminal and the server should start up and log “Wizardry happening on port 5001” or whatever you put as the PORT number!
Time to Add Some Routes to the Server and Set-Up a Basic API
The first thing we’ll do is add a GET route to the server’s root path.
This is the route that Azure will later use to serve your Create-React-App frontend!!!
At the root of the project, create an index.html file that we will temporarily use to serve to the client.
After that, we are ready to add the GET / route to server.js so we can serve clients the sample index.html we just created.
Save everything and restart your server in the terminal (Ctrl+C and then re-run yarn start!).
Now we want to test if the server correctly serves our web page. For this step you can either use Postman or your favorite browser.
Awesome! We can serve a webpage with our Express server now. Lets go ahead and connect our Express server to Azure Cosmos DB and set-up a simple API to interact with the DB.
With that being said, lets go over to the Azure Portal and create an Azure Cosmos DB resource
Once your Cosmos resource is created, go to it, and in the second section under Settings, click on Connection String. In here we are going to copy values into our .env file.
Paste the Username, Primary Password and Primary Connection String into the respective places in .env file
The next thing we want to do is create a folder named
server
at the project root to hold the server-side logic. In this folder I usually put anything that has to do with a DB or utility files for server.js.
Ok so let’s now create a file in the server
directory named db-conn.js
to connect to the Azure Cosmos DB and then we will create a Model with Mongoose to shape what we save into the Document DB!
First off, we are going to use a package called MongooseJS, an object modeler for MongoDB (remember we chose to use MongoDB API with CosmosDB earlier!). This package will connect us to the DB, allow us to CRUD the DB via models we create(so we know what the hell we’re dealing with) and yeah. Lets go ahead and add that package to the server by running yarn add mongoose
.
This is all within the server folder!
Lets create that file db-conn.js
now and use mongoose to connect to the Cosmos DB. We’ll be using those environment variables we set up earlier.
After creating db-conn.js
, we will require() it in server.js, restart the server via the terminal and viola! Connection to Cosmos.
Awesome! Now we have a server that can serve a webpage and is connected to Azure’s cloud DB. Let’s use mongoose to create a model that we can then use to save documents into the database.
Time to work on a simple API that uses this model to interact with the DB. Create a folder in the server dir named routes
. We will have one file in this folder named thoughts-route.js
. This file will be used on the server to mount the routes it defines. The routes it defines will enable the server to CRUD the DB.
Ok! We can now restart the server and test out the API. Use Postman or your favorite HTTP tool and make a POST to seed data into the DB.
After the data is seeded, run the GET request (the first route in thoughts-route) to get an array of all Thoughts. You can play with the other routes and/or create your own.
That is about it for the server. To recap:
- Created server.js at project root
- Did configuration for package.json and git repo
- Created server folder to house server logic (Database connection, models, routes to interact with DB/other APIs, etc)
- Created Azure Cosmos Resource
We’ll Be Back Server! Create-React-App (CRA) Time
Let’s keep the server running in it’s terminal, open a new terminal and navigate to the project root and create a new folder named client
and cd
into it. The client directory is where we will house the CRA. Within the client directory, we will run npx create-react-app CRA_NAME in the terminal and then cd
into APP_NAME when it is done creating.
Now we’ll get the client ready to communicate with our backend (the server should be running in a different terminal and PORT and the CRA should also be running in a different terminal and PORT). We’ll add a package named axios
to make HTTP requests to our server and a proxy
variable to package.json
so the client knows where to send the requests!
* Note that the package.json
within the CRA separates the packages that are needed by the client only from the packages needed by server.js
at the root*
Ok, now let’s create a simple React component to interact with the server API we made earlier.
We will use App.js for this. Replace it’s current contents with the below. (You will be able to copy/pasta from my GitHub!)
Awesome! We now have a simple MERN stack application to play with, hopefully😅. I’ll gladly answer questions in the comments below if any assistance is needed!
One thing to note is that in our development environment we are running a local development server for the client on one PORT and our Express server on another PORT. If you do not have the server running while using the buttons, you will see error alerts.
However, in our production environment in Azure WebApp we will only have one web server!! This is because in production, the web server or Express server we built (server.js
) will serve clients that request to (by visiting your .azurewebsites.net domain) your Create-React-App index.html
.
Remember, we did an example of this concept earlier with Postman or your favorite browser and it should still be implemented for your server right now. Test it out again!
Running yarn run build
package.json script to get a production ready index.html
.
NOTE!! This step is purely for understanding/visualizing what is happening for later. The build folder that is created by this step is in the .gitignore and can be deleted after this step
Let’s go ahead and run the command yarn run build
in a terminal within the client/CRA_NAME
directory. This command uses the react build script to make a directory named build
which will contain a minified bundled version of your application which is accessible via index.html
. This is the file that our Express server will serve when clients browse to our site!
Now let’s make a few minor adjustments to get the app ready for production!
We are going to change the scripts
in the root server package.json. We are doing this because Azure WebApp uses this start script by default when starting your server! We basically tell the server upon start “Hey, change into my client/CRA_NAME
directory, install all the needed packages, build a production ready index.html, navigate back to the server root and start the server”. Easy peezy huh. We also added a dev script for development purposes since we just had to modify the start script.
We add express static middleware so the server has access to static files the client requires in client/CRA_NAME/build
EDIT:
Using the express.static
middleware on the server allows the server to serve static assets from the specified directory. This middleware has a configurable option to set the index
property which specifies which file to serve upon visiting the server root. By default this is set to index.html
. What this means is we don’t even need to specify a GET /
route handler to serve the Create-React-App client as mentioned in this article. You will find that with or without the GET /
route, you can access the page. It will be served automagically as long as you decide to use the express.static
middleware default options.
We are also going to change the path of the index.html
we use in server.js
GET /. It needs to point to the client/CRA_NAME/build
directory now and not the test index.html
at the root of the project we created earlier. This file can be deleted if you like.
We should now be ready to commit our changes to the repo (hopefully you committed along the way unlike me 😅) and then create our Azure WebApp resource
Head back over to your Azure portal, find ‘App Services’ in the left pane, and click ‘Add’. This is the Azure resource used to host the site.
Once your resource is created, navigate to it and let’s go ahead and add the environmental variables from our .env file to it! We do this in ‘Application Settings’ > ‘Add New Setting’. Remember to always keep .env files in .gitignore!
Go ahead and SAVE at the top left and once that is done, navigate to ‘Deployment Options’ under the Deployment section. This is where we will connect our repo to the resource so the resource can pull our code from the master branch!
Once you have successfully followed the GUI and connected your repo you can see your commits on master in ‘Deployment Options’, manually sync, etc. This is where the magic happens when you push to master!
Let’s check out Kudu, an “Advanced Tool” we can use to see info on the cloud server our app is running on. It says “Advanced” but it can be easy to use for purposes like ours. We are going to use Kudu to look at our filesystem for the app and make sure that the client successfully installs its needed modules and creates the build folder.
NOTE: pushing to master will run the start script which installs modules and builds every time to my belief so far. This while cause your site to respond with Service Unavailable while it is down and building the client again if clients try to access it so plan to push to master at low use hours. There are advanced options you can use to get around this like multiple deployment slots!
To access Kudu scroll down to the section ‘Developer Tools’ and click ‘Advanced Tools’ and Lets a Go!
You will land on a page that looks something like this and contains details about your app
Now navigate to Files > url_stuffs/site > url_stuffs/wwwroot and you should notice a directory structure just like in development! I use this to tell if the site has built the client directory build or not. Site up time is another useful one!
Once you notice your client has successfully ran the build and installed node_modules you should be good to go.
A good way to navigate to your site is through the ‘Overview’ section in the Azure portal for your resource via the ‘Browse’ button.
And there she is! A beautiful result. You can visit this page at https://mern-azure-example.azurewebsites.net/
I like how anyone can just nuke all the Thoughts. Nice…nice 🤪. Knowing that, how much thought will you put into the Thought you post? And if someone nukes them, would it truly be time wasted?! Don’t forget to leave a more permanent Thought over at my website https://wickedworlok-therollingtray.azurewebsites.net/! Whatever is on the brain.
I hope this article helps someone. Till the next one, Peace.
Helpful Links:
- My GitHub: https://github.com/ChrisLFieldsII/mern-azure-example
- Learn Mongoose: https://mongoosejs.com/docs/index.html
- Learn Express: https://expressjs.com/en/starter/installing.html
- Learn React: https://reactjs.org/
- Learn Node: https://nodejs.org/en/docs/
- Learn Microsoft WebApp: https://azure.microsoft.com/en-us/services/app-service/web/
- Learn Microsoft Cosmos DB: https://docs.microsoft.com/en-us/azure/cosmos-db/create-mongodb-nodejs