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.
If you are new to typescript, watch this tutorial which covers the basics of TypeScript.
Firstly, you need to install typescript in your machine. Run the following command, this will install typescript globally in your machine.
1npm install -g typescript
Create a directory and initialize the node.js application with the command.
1npm init --yes
After that, you need to create a configuration file for typescript which compiles the typescript into javascript.
1tsc --init
it will create a configuration file called tsconfig.json which contains the TypeScript configuration for the application.
Further, the configuration file contains the compiler options which can be configured. important options are,
Once, it is configured. we need to install few dependencies to setup and run the typescript on express application.
Install the following dependencies using the command
1npm i -D typescript ts-node @types/node @types/express
After that, create a scripts in package.json to compile and run the application.
1"scripts": {2 "dev": "ts-node src/app.ts",3 "start": "ts-node dist/app.js",4 "build": "tsc -p ."5 }
Once TypeScript configuration is done, we can build the Express application using TypeScript.
Create a directory called src which contains the TypeScript files and add the app.ts file in that.
1import express, { Application, Request, Response, NextFunction } from "express"2import bodyParser from "body-parser"34const app: Application = express()56app.use(bodyParser.json())7app.use(bodyParser.urlencoded({ extended: true }))89app.get("/", (req: Request, res: Response) => {10 res.send("TS App is Running")11})1213const PORT = process.env.PORT1415app.listen(PORT, () => {16 console.log(`server is running on PORT ${PORT}`)17})
one of the advantages of using TypeScript is defining the Type for the variable(Static Checking).
Here Express instance will be of type Application, Therefore, variable must be of type Application. same goes for Request,Response and Next Function(Middleware).
After that, we need to write a logic to connect the database. create a file called connect.ts and add the following code,
1import mongoose from "mongoose"23type DBInput = {4 db: string,5}67export default ({ db }: DBInput) => {8 const connect = () => {9 mongoose10 .connect(db, { useNewUrlParser: true })11 .then(() => {12 return console.info(`Successfully connected to ${db}`)13 })14 .catch(err => {15 console.error(`Error connecting to database :`, err)1617 return process.exit(1)18 })19 }2021 connect()2223 mongoose.connection.on("disconnected", connect)24}
DBInput is a type which takes variable db as a string. we use it connect with mongodb.
After that, create directories Controllers,Models ,Routes and types in the root directory.
create a file User.mode.ts in Models Directory and add the following code,
1import mongoose, { Schema, Document } from "mongoose"23export interface IUser extends Document {4 email: String;5 firstName: String;6 lastName: String;7}89const UserSchema: Schema = new Schema({10 email: {11 type: String,12 required: true,13 unique: true,14 },15 firstName: {16 type: String,17 required: true,18 },19 lastName: {20 type: String,21 required: true,22 },23})2425export default mongoose.model < IUser > ("User", UserSchema)
Firstly, we define mongoose schema for user model and User Interface
In Controllers Directory, Create User.controller.ts file and add the following code
1import User,{ IUser } from '../Models/User.model';23interface ICreateUserInput {4 email: IUser['email'];5 firstName: IUser['firstName'];6 lastName: IUser['lastName'];7}89async function CreateUser({10 email,11 firstName,12 lastName13 }: ICreateUserInput): Promise<IUser> {14 return User.create({15 email,16 firstName,17 lastName18 })19 .then((data: IUser) => {20 return data;21 })22 .catch((error: Error) => {23 throw error;24 });25 }2627 export default {28 CreateUser29 };
After that, create a file index.ts in Routes directory and add the following code,
1import { RoutesInput } from "../types/route"2import UserController from "../Controllers/User.controller"34export default ({ app }: RoutesInput) => {5 app.post("api/user", async (req, res) => {6 const user = await UserController.CreateUser({7 firstName: req.body.firstName,8 lastName: req.body.lastName,9 email: req.body.email,10 })1112 return res.send({ user })13 })14}
RoutesInput is a custom type which defines the Express Application Type.
create a file types.ts in types directory and add the code,
1import { Application } from "express"2export type RoutesInput = {3 app: Application,4}
update the app.ts with mongodb connection and routes of the application.
1import express, { Application, Request, Response, NextFunction } from "express"2import "dotenv/config"3import bodyParser from "body-parser"4import Routes from "./Routes"5import Connect from "./connect"67const app: Application = express()89app.use(bodyParser.json())10app.use(bodyParser.urlencoded({ extended: true }))1112app.get("/", (req: Request, res: Response) => {13 res.send("TS App is Running")14})1516const PORT = process.env.PORT17const db = "mongodb://localhost:27017/test"1819Connect({ db })20Routes({ app })2122app.listen(PORT, () => {23 console.log(`server is running on PORT ${PORT}`)24})
To test the application, run the script npm run dev and visit the url http://localhost:4000
If you are new to docker, read about docker for node.js and docker configuration.
create a file Dockerfile in the root directory and add the following code.
1FROM node:1023WORKDIR /usr/src/app45COPY package.json ./67RUN npm install89RUN npm install pm2 -g1011RUN npm run build1213COPY ./dist .1415EXPOSE 40001617CMD ["pm2-runtime","app.js"]
Basically, we take the node base image and install all our dependency in the docker image container
After that, we install process manager called pm2 which is used mostly in all production applications. then we copy the compiled code from local to docker image.
Further, create a file docker-compose.yml in the root directory and add the following code.
1version: "3"23services:4 app:5 container_name: app6 restart: always7 build: .8 environment:9 - PORT=400010 ports:11 - "4000:4000"12 links:13 - mongo14 mongo:15 container_name: mongo16 image: mongo17 ports:18 - "27017:27017"
Docker compose combine multiple docker services and run it in a single container. Here, we combine MongoDB and Application images and run it container.
Once, Dockerfile is added. run the following command,
1docker-compose up
it will deploy the compiled code in docker image and run it in the container.
Complete Source code contains Building a Production - Ready Node.js App with TypeScript and Docker.
No spam, ever. Unsubscribe anytime.