Complete guide to deploy a simple full stack application in Docker
Tags: react, docker, node, express
Published: 2021-08-05 17:03:48

## Table of contents
* [Create a simple todo UI using React.] (#create-frontend)
* [Create a simple backend server using Express.] (#create-backend)
* [Connect Frontend and Backend.] (#connect)
* [Create UI bundle and serve it through Express server.] (#build)
* [Run the application in Docker] (#run)


### Creating a simple TODO app using React. <a name=create-frontend> </a>
We will be using create-react-app to quickly setup a react application with basic dependencies installed.

Command to create the app
```
npx create-react-app frontend
```

This will create folder named frontend containing all the basic files with dependencies installed.

Two more dependencies are required:
1. axios : To make API calls. fetch call also be used.
2. uuid : To generate random IDs for todo tasks.

commands to install the above
```
npm install --save axios
npm install --save uuid
```

Below is the simple UI code which has 
1. A text input box to take the task name.
2. A "Add" button to add new tasks.
3. List of previously created tasks with "Delete" button to delete the tasks.

{% gist https://gist.github.com/SagarTrimukhe/c99ff4881a5c8abd67a851dff1d08af6.js %}


This is how it will look (No fancy colors or animations)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bs3gfg9r6i74gsitylrb.png)
 

API handlers are maintained in a separate file.
{% gist https://gist.github.com/SagarTrimukhe/fc3145c6c7b712d41dd955fa05113dfe.js %}


### Creating a server using Express.js <a name=create-backend></a>

Let's start with a folder creation named backend.
1. cd into the folder
   cd backend

2. Run "npm init" command to create a package.json file

3. When the above command is ran, it will ask for few details. All can be skipped by hitting enter.

3. Run "npm install --save express" to install the express js dependency. 

4. By default the entry point of the application will be pointing to "index.js". It can be changed by editing the package.json file
"main": "your_file_name.js"

5. Create a file index.js (or your_file_name.js)

6. Following is the simple express js code with 3 APIs.

{%gist https://gist.github.com/SagarTrimukhe/359078717dd3761b67a07db9dcdc6cb0.js  %}

It has 
a. GET /tasks endpoint to get the list of tasks.
b. POST /tasks to create a new task.
c. DELETE /tasks to delete a task.

All the tasks are stored in-memory. The tasks data will be lost as soon the server is stopped.
(So, NOT exactly a FULL STACK application)

To start the server run following command
```
node index.js
```

You can test APIs using a REST Client like [Postman](https://learning.postman.com/docs/getting-started/introduction/) or simple CURL commands.


### Connecting frontend and backend. <a name=connect></a>
Even though the correct endpoints are mentioned in UI, it will not be able to reach the backend APIs due to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).

To solve this we need to use a proxy.
It is very simple to proxy the calls by just updating the UI package.json file.

Add the below configuration.
```
 "proxy": "http://localhost:4000"
```

Now the UI should be able to connect to backend APIs.


### Generating the UI bundle and serving it through express. <a name=build></a>
Generating production UI bundle is dead simple
Run the below command.

```
npm run build
```
This is will create a folder named build in your frontend root directory containing index.html file along with JavaScript and CSS files.

This can be served using a static server like "serve" package.

BUT, the UI will not be able to reach backend servers.
BECAUSE, proxy feature is available only in development mode.

To solve this issue, we can serve the UI using same express server. YES you read it right. a single server to server both frontend and backend.

To do so, 
1. Copy the build folder to backend folder
2. Add the following line in index.js file
```
app.use(express.static('build'));
```
We can give the absolute path also, just keeping it simple here :)

Now start the express server. At '/' path the UI will be served and at other paths, the APIs will be available.


### Deploying the application in a container. <a name=run></a>
Till now we have developed and deployed the application on local machine.

If you are a docker guy, then we can quickly deploy this application in a container as well.

* Create a Dockerfile.
Dockerfile is a simple text file containing all the commands to create a docker image.
The following is a docker file which uses alpine OS as a base image and exposes the port 4000.

{%gist https://gist.github.com/SagarTrimukhe/b9a61b595e2c86383c8f1fc1b5f0756e.js %}

* Create a docker image
Run the command to build the image
```
docker image build -t todoapp:1.0 .
```

* Start the container
Once the image is created, next step is to create a container.
Run the command to create and start the container.
```
docker container run -d -p 8000:4000 todoapp:1.0
```

4. If the docker is running on a VM then the application can be accessed at VM-IP-Address:8000
eg. http://192.168.43.18:8000


Complete project is available at: https://github.com/SagarTrimukhe/todo-app