/docker-react-with-express-api

Starter Application: Two-container React frontend backed by a Node Express-served API with Docker Compose

Primary LanguageJavaScript

React Frontend Backed by Express API with Docker Compose

This is a two-container web application consisting of React frontend served with Nginx and an API served with Express from a Node container. This is merely intended to serve as a jumping-off point for building such an application, and it comes ready with a test endpoint being used to pull information into the frontend.

Setup

we'll assume Docker is already installed.

Install Docker Compose

These steps were pulled right from the Docker documentation.

  1. Install Docker Compose.

First, you may want to check the current release and replace the 1.23.2 in the command below if necessary.

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  1. Make it executable.

Next, set the permissions to make the binary executable:

$ sudo chmod +x /usr/local/bin/docker-compose
  1. Verify it's working as expected.

Then, verify that the installation was successful by checking the version:

$ docker-compose --version

This will print out the version you installed:

docker-compose version 1.23.2, build 1110ad01

Application Setup

Clone

Fork and clone this repo.

$ git clone https://github.com/mbwatson/docker-nginx-react-node-api.git

Set up environment variables file

Make an environment variables file named .env. There's a sample one--.env.sample--in place that will work for development out of the box, so just copy that.

$ cp .env.sample .env

This file contains a couple environment variables: NODE_ENV and API_PORT. The NODE_ENV is set to development by default and can be (and is) overridden in the production Compose file. The API_PORT specifies the port to esrve the API on.

Start

There are two services to run--they are named frontend and api.

Development

Start both services:

$ docker-compose up

The above command starts and attaches to the three containers and results in output like the following.

Recreating node ... 
Recreating react ... 
Recreating react
Recreating react ... done
Attaching to project-api, project-frontend
project-api | 
project-api | > api@1.0.0 start /usr/src/app
project-api | > nodemon app
project-api | 
project-api | [nodemon] 1.18.9
project-api | [nodemon] to restart at any time, enter `rs`
project-api | [nodemon] watching: *.*
project-api | [nodemon] starting `node app.js`
project-api | 
project-api | Shhh... I'm listening on port 3030.
project-api | 
project-frontend | 
project-frontend | > app@0.1.0 start /usr/src/app
project-frontend | > react-scripts start
project-frontend | 
project-frontend | Starting the development server...
project-frontend | 
project-frontend | Compiled successfully!
project-frontend | 
project-frontend | You can now view app in the browser.
project-frontend | 
project-frontend |   Local:            http://localhost:3000/
project-frontend |   On Your Network:  http://192.168.240.3:3000/
project-frontend | 
project-frontend | Note that the development build is not optimized.
project-frontend | To create a production build, use npm run build.
project-frontend | 

  .
  .
  .

If necessary, it will build the images first.

Possibly Useful Notes

It's nice to leave your session attached to keep an eye on errors, but of course you want to rebuild and/or detach at times:

$ docker-compose up --build -d

Or only start a single services, specify it explicitly:

$ docker-compose up api

The above command starts only the api. This is nice if you want to test the API with a tool like Postman.

You can also just build a specific image.

$ docker-compose up --build frontend

Anyway, after starting both containers. Point your browser to http://localhost:3000 to see the React application. To mess with the API directly (in the browser or with something like Postman, say), that is served to http://localhost:3030, replacing the 3030 with another port if you made a change to .env above.

Verify it Works

Notice now if everything is working correctly. You should a rotating React logo, much like the out-of-the-box result from running Create React App. You should also see a "Response from API" block with "You hit the API test endpoint!" displayed.

Trace the Communication

That text is being served from the api container, and you can trace the entire interaction to make sense of the communication between the containers.

On the frontend, you see that /frontend/src/App.js uses the ApiTestCard component, which receives the test endpoint as a prop, which in turn makes the call (with Axios) to the test endpoint, and then shows the response on the page.

On the backend you can trace the call to the test endpoint through /api/app.js to /api/routes/test.js to /api/controllers/test.js.

Hot Reloading

Note the development frontend and api services start with React's development server and Nodemon, respectively, allowing hot reloading. This is great for speeding up the development process, which can take place entirely within the containers. The source files are mapped to the host machine, however, so you can also develop outside the containers. It is, however, necessary to rebuild the images during development if new modules are installed.

Installing New Node Modules

If, for example, you execute npm install some-tool to install a module (which would of course be done from within the frontend/ directory), the next time docker-compose up is run, the --build flag will need to be used so that some-tool is installed on the image before the container spins up.

Alternatively, you could circumvent this by logging into the running react container and npm install it there in (the default location) /usr/src/app.

Production

Start both services by specifying the production-specific Docker Compose file, docker-compose.prod.yml:

$ docker-compose -f docker-compose.prod.yml up --build -d

This serves the frontend to port 80 on the host, and is thus reachable simply at http://localhost. The API is publicly accessible via http://localhost/api because the Nginx reverse proxies requests to /api/ to port 3030 in the api container.

Tear it Down

If you started without the detach flag, -d, you can stop the containers running with CTRL+C, and Docker will clean up after itself. If you ran things in detched mode (with the -d flag), then bring everything down with the following command.

$ docker-compose down

References

Links to some tools used in this project are below.