Blog hero

Backend Scaffolding with Typescript

A Complete guide on how to setup your backend API

10 min read

Create a Hello World REST API

start by creating your project directory and navigating into it:

mkdir my-backend-api
cd my-backend-api
mkdir src
mkdir dist

Initialize a new Node.js project:

npm init -y

Install TypeScript , type definitions and tsx all as development with the -D flag install express as a project dependency

npm install typescript @types/node @types/express tsx -D
npm install express

Create a tsconfig.json file in the root of your project: you can do this by running the following command:

npx tsc --init 

Open the tsconfig.json file and update the following settings:

{
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
  }
}

Create a new file src/index.ts and add the following code:

import express from 'express';

const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Compile the TypeScript code and run the server:

npx tsc
node dist/index.js

Navigate to http://localhost:3000 in your browser, and you should see the message Hello World! displayed on the screen.

Congratulations! You have successfully created a simple REST API using TypeScript and Express.

Now we're going to set up a way to automatically compile and run our code every time you save a file. This will save you time and make your development process more efficient. For this we we'll use the tsx package we installed.

Let's add 3 new script to your package.json file:

  • dev: This script will use the tsx command to watch for changes in the src/index.ts file and automatically compile and run the code every time you save a file.
  • build: This script will use the tsc command to compile the TypeScript code.
  • start: This script will use the node command to run the compiled code in the dist/index.js file.
"scripts": {
    "dev": "tsx --watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  },

Version Control with Git & Gitignore

Initialize a new git repository in your project directory:

git init

Create a .gitignore file in the root of your project and add the following entries:

node_modules
dist

Add all files to the staging area and commit them:

git add .
git commit -m "Initial commit"

Containerize your API

Create a Dockerfile in the root of your project, and add the following code:

FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]

This will use Node 20, set up the working directory, copy the package.json and package-lock.json files, install the dependencies, copy the rest of the files, expose port 3000, and run the start script.

  1. Build and Run the Docker Image

Build the Docker image:

docker build -t my-backend-api .

Run the Docker container:

docker run -p 3000:3000 my-backend-api

Now you can access your API at http://localhost:3000.

Setting up Live reload inside Docker

To enable live reload inside the Docker container, you need to mount the source code directory as a volume in the container. This will allow the container to watch for changes in the source code and automatically reload the server**.**

let's start by creating a compose.yaml file in the root of your project:

version: '3.8'

services:
  my-backend-api:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src
    command: npm run dev

This will build the Docker image, expose port 3000, mount the src directory as a volume, and run the dev script.

Run the Docker container using Docker Compose:

docker-compose up

Now you can access your API at http://localhost:3000 and make changes to the source code without restarting the server.

Setup Linting, Formatting, Conventional Commits, and Pre-commit Hooks

Install the following packages as development dependencies:

npm install eslint prettier eslint-config-prettier eslint-plugin-prettier husky lint-staged @commitlint/cli @commitlint/config-conventional -D

Create an .eslintrc.json file in the root of your project and add the following code:

{
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint"],
  "rules": {
    "prettier/prettier": "error"
  }
}

Create a .prettierrc file in the root of your project and add the following code:

{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all"
}

Create a .lintstagedrc file in the root of your project and add the following code:

{
  "*.{js,ts}": [
    "eslint --fix",
    "prettier --write"
  ]
}

Create a .huskyrc file in the root of your project and add the following code:

{
  "hooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}

Create a commitlint.config.js file in the root of your project and add the following code:

module.exports = {extends: ['@commitlint/config-conventional']};

Add the following scripts to your package.json file:

"scripts": {
    "lint": "eslint . --ext .js,.ts",
    "format": "prettier --write .",
    "commit": "git-cz"
  },

Setup Testing

Setup Environment Variables

Setup Logging and Monitoring

Setup API & Code Documentation

Setup Continuous Integration and Deployment

Things you'll need to get started:

  • Node.js
  • TypeScript
  • Express.js

Create a new directory for your project and navigate into it:

Ready to work together?

Lets hop on a zoom call and discuss your project at no cost.