Building a Production - Ready Node.js App with TypeScript and Docker
Tags: showdev, webdev, tutorial, beginners
Published: 2019-09-28 07:55:31

---
title: Building a Production - Ready Node.js App with TypeScript and Docker
published: true
description: Building a Production - Ready Node.js App with TypeScript and Docker
tags: showdev,webdev,tutorial,beginners
canonical_url : https://cloudnweb.dev/2019/09/building-a-production-ready-node-js-app-with-typescript-and-docker/
---

<!-- wp:paragraph -->
<p>In this article, we will see how to build a Node.js, TypeScript Application and deploy it to server with Docker. Building a Production - Ready Node.js App with TypeScript and Docker.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you are new to typescript, <a href="https://www.youtube.com/watch?v=ahCwqrYpIuM">watch </a>this tutorial which covers the basics of TypeScript.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Application Setup</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Firstly, you need to install typescript in your machine. Run the following command, this will install typescript globally in your machine.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>npm install -g typescript </code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Create a directory and initialize the node.js application with the command.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>npm init --yes</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>After that, you need to create a configuration file for typescript which compiles the typescript into javascript.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>tsc --init</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>it will create a configuration file called <strong>tsconfig.json</strong> which contains the TypeScript configuration for the application.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Configuring TypeScript</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Further, the configuration file contains the compiler options which can be configured. important options are,</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>target</strong> - it can be either ES6 or ES5, based on the options, TypeScript compiles the code either to ES6 or ES5.</li><li> <strong>outDir </strong>- it specifies the directory where the compiled code will be stored.</li><li> <strong>rootDir </strong>- it specifies directory on which the typescript code will be.</li><li> <strong>moduleResolution </strong>- specifies the module resolution strategy</li></ul>
<!-- /wp:list -->

<!-- wp:image {"id":1400} -->
<figure class="wp-block-image"><img src="https://cloudnweb.dev/wp-content/uploads/2019/09/config-ts.png" alt="" class="wp-image-1400"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Once, it is configured. we need to install few dependencies to setup and run the typescript on express application.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Install the following dependencies using the command</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>npm i -D typescript ts-node @types/node @types/express</code></pre>
<!-- /wp:code -->

<!-- wp:list -->
<ul><li><strong>ts-node</strong> - it is a package for using TypeScript with Node.js. we can run the application using <strong>ts-node app.ts</strong></li><li><strong>@types/node</strong> - it defines the custom types for Node.js in typescript</li><li><strong>@types/express</strong> - it defines the custom types for express application in typescript</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>After that, create a scripts in package.json to compile and run the application.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>"scripts": {
    "dev": "ts-node src/app.ts",
    "start": "ts-node dist/app.js",
    "build": "tsc -p ."
  }</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3> Building Express Application with TypeScript</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Once TypeScript configuration is done, we can build the Express application using TypeScript.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a directory called <strong>src</strong> which contains the TypeScript files and add the <strong>app.ts</strong> file in that.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import express,{ Application,Request,Response,NextFunction } from 'express';
import bodyParser from 'body-parser';

const app : Application = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));


app.get('/',(req:Request,res : Response ) => {

    res.send('TS App is Running')
})

const PORT = process.env.PORT;


app.listen(PORT,() => {
    console.log(`server is running on PORT ${PORT}`)
})</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>one of the advantages of using TypeScript is defining the Type for the variable(Static Checking). </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here Express instance will be of type <strong>Application</strong>, Therefore, variable must be of type Application. same goes for <strong>Request</strong>,<strong>Response</strong> and <strong>Next Function</strong>(Middleware).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After that, we need to write a logic to connect the database. create a file called <strong>connect.ts</strong> and add the following code,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import mongoose from 'mongoose';

type DBInput = {
    db : string;
}

export default({db} : DBInput) => {
    
    const connect = () => {
        mongoose
            .connect(db,{ useNewUrlParser : true })
            .then(() => {
                return console.info(`Successfully connected to ${db}`);
            })
            .catch((err) => {
                console.error(`Error connecting to database :`,err);

                return process.exit(1);
            })
    };

    connect();

    mongoose.connection.on('disconnected',connect);
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><strong>DBInput </strong>is a type which takes variable db as a string. we use it connect with mongodb.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After that, create directories <strong>Controllers</strong>,<strong>Models</strong> ,<strong>Routes</strong> and <strong>types</strong> in the root directory.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Controllers</strong> - contains all the business logic for the application</li><li><strong>Models</strong> - contains all the Database Schema of Mongoose.</li><li><strong>Routes</strong> -  will have all the API Routes for the application</li><li><strong>Types</strong> -  will contains Custom types used in the Application</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>create a file <strong>User.mode.ts</strong> in <strong>Models </strong>Directory and add the following code,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code> import mongoose, { Schema,Document } from 'mongoose';

 export interface IUser extends Document {
     email : String;
     firstName : String;
     lastName : String;
 }

 const UserSchema : Schema = new Schema({
     email : {
         type : String,
         required : true,
         unique : true
     },
     firstName : {
         type : String,
         required : true
     },
     lastName : {
         type : String,
         required : true
     }
 });

 export default mongoose.model&lt;IUser>('User',UserSchema);</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Firstly, we define mongoose schema for user model and User <strong><a href="https://www.youtube.com/watch?v=P17bFRuefjA">Interface</a></strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In <strong>Controllers </strong>Directory, Create <strong>User.controller.ts</strong> file and add the following code</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>
import User,{ IUser } from '../Models/User.model';

interface ICreateUserInput {
    email: IUser['email'];
    firstName: IUser['firstName'];
    lastName: IUser['lastName'];
}

async function CreateUser({
    email,
    firstName,
    lastName
  }: ICreateUserInput): Promise&lt;IUser> {
    return User.create({
      email,
      firstName,
      lastName
    })
      .then((data: IUser) => {
        return data;
      })
      .catch((error: Error) => {
        throw error;
      });
  }
  
  export default {
    CreateUser
  };</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>After that, create a file index.ts in Routes directory and add the following code,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import { RoutesInput } from '../types/route';
import UserController from '../Controllers/User.controller';

export default ({ app } : RoutesInput) => {

    app.post('api/user',async(req,res) => {
        const user = await UserController.CreateUser({
            firstName: req.body.firstName,
            lastName: req.body.lastName,
            email: req.body.email
          });
      
          return res.send({ user });
    })
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><strong>RoutesInput</strong> is a custom type which defines the Express Application Type.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>create a file <strong>types.ts </strong>in <strong>types </strong>directory and add the code,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import { Application } from 'express';
export type RoutesInput = {
  app: Application;
};</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>update the <strong>app.ts</strong> with <strong>mongodb </strong>connection and <strong>routes </strong>of the application.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>import express,{ Application,Request,Response,NextFunction } from 'express';
import "dotenv/config";
import bodyParser from 'body-parser';
import Routes from './Routes';
import Connect from './connect';

const app : Application = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));


app.get('/',(req:Request,res : Response ) => {

    res.send('TS App is Running')
})

const PORT = process.env.PORT;
const db = 'mongodb://localhost:27017/test';


Connect({ db });
Routes({ app })

app.listen(PORT,() => {
    console.log(`server is running on PORT ${PORT}`)
})</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>To test the application, run the script <strong>npm run dev</strong> and visit the url <strong>http://localhost:4000</strong></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Docker Configuration</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>If you are new to docker, read about <a href="https://cloudnweb.dev/2019/04/dockerizing-a-node-js-web-app/">docker for node.js</a> and <a href="https://cloudnweb.dev/2019/06/replacing-docker-with-podman-power-of-podman/">docker configuration</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>create a file <strong>Dockerfile</strong> in the root directory and add the following code.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM node:10

WORKDIR /usr/src/app

COPY package.json ./

RUN npm install

RUN npm install pm2 -g

RUN npm run build

COPY ./dist .

EXPOSE 4000

CMD ["pm2-runtime","app.js"]</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Basically, we take the node base image and install all our dependency in the docker image container</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After that, we install process manager called <a href="https://cloudnweb.dev/2019/09/pm2-for-node-js-developers/">pm2 </a>which is used mostly in all production applications. then we copy the compiled code from local to docker image.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Further, create a file <strong>docker-compose.yml</strong> in the root directory and add the following code.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>version: "3"

services:
  app:
    container_name: app
    restart: always
    build: .
    environment: 
      - PORT=4000 
    ports: 
      - "4000:4000" 
    links: 
      - mongo
  mongo:
    container_name: mongo
    image: mongo
    ports:
      - "27017:27017"      </code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><a href="https://docs.docker.com/compose/">Docker compose</a> combine multiple docker services and run it in a single container. Here, we combine MongoDB and Application images and run it container.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Docker Deployment and Running</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Once, Dockerfile is added. run the following command,</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>docker-compose up</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>it will deploy the compiled code in docker image and run it in the container.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Complete Source <a href="https://github.com/ganeshmani/express-typescript-docker">code</a> contains Building a Production - Ready Node.js App with TypeScript and Docker.</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<a href="https://click.linksynergy.com/link?id=YIJ5oggSvpI&offerid=507388.1587718&type=2&murl=https%3A%2F%2Fwww.udemy.com%2Fadvanced-node-for-developers%2F"><IMG border=0 src="https://i.udemycdn.com/course/480x270/1587718_8fdf.jpg" ></a><IMG border=0 width=1 height=1 src="https://ad.linksynergy.com/fs-bin/show?id=YIJ5oggSvpI&bids=507388.1587718&type=2&subid=0" >
<!-- /wp:html -->