DEV Community

Arsalan Ahmed Yaldram
Arsalan Ahmed Yaldram

Posted on

Setup express with Typescript - controllers and routes

Introduction

In this series we will setup an express server using Typescript, we will be using TypeOrm as our ORM for querying a PostgresSql Database, we will also use Jest and SuperTest for testing. The goal of this series is not to create a full-fledged node backend but to setup an express starter project using typescript which can be used as a starting point if you want to develop a node backend using express and typescript.

Overview

This series is not recommended for beginners some familiarity and experience working with nodejs, express, typescript and typeorm is expected. In this post which is part two of our series we will set up routing and controllers, we will cover the following : -

  • Setup environment variables and dotenv.
  • Add todo controller.
  • Add todo routes.
  • Register the todo routes in our express app.

Step One: Setup environment variables

In the last tutorial we hardcoded the server port in our app.ts, but as you all know we store all such information in environment variables. Similarly we store database credentials, logging levels all in environment variables. This comes handy when we deploy our applications to multiple environments like dev, staging, test, production we only need to tweak are the environment variables for each environment. In your terminal run

npm install --save dotenv
Enter fullscreen mode Exit fullscreen mode

Then under app.ts import the dotenv package, make sure this is the first import in our file : -

import "dotenv/config"
Enter fullscreen mode Exit fullscreen mode

Now create 2 files namely .env & .env.sample, both in the root of our project not under src. Make sure you add .env to the .gitignore file which we did in the previous tutorial. .env and .env.sample will have the same keys only difference is that .env has values and .env.sample will only have keys. This makes it handy so that we can commit .env.sample to git.

Under .env file paste the following : -

NODE_ENV=development
SERVER_PORT=8080
Enter fullscreen mode Exit fullscreen mode

Under .env.sample paste the following : -

NODE_ENV=
SERVER_PORT=
Enter fullscreen mode Exit fullscreen mode

Now in app.ts file for the port variable we do : -

private readonly port = process.env.SERVER_PORT || 8080
Enter fullscreen mode Exit fullscreen mode

Step Two: Add Todo Controller

Lets create a new folder under src called api and under api folder create another folder called todos. Inside the todos folder create a new file called todos.controller.ts and paste the following code : -

import { Request, Response } from 'express'

const todos = [
   {
     id: '1',
     text: 'Run daily for 15 minutes',
   },
   {
     id: '2',
     text: 'Buy coffe',
   },
]

class TodoController {
  getAllTodos(req: Request, res: Response) {
   return res.status(200).json({
      status: true,
      statusCode: 200,
      todos,
    })
  }

  getTodoById(req: Request, res: Response) { 
    const { id } = req.params
    const todo = todos.find((todo) => todo.id === id)
    if (!todo) {
     return res.status(404).json({
       status: false,
       statusCode: 404,
       message: `todo not found for id - ${id}`,
     })
    }

     return res.status(200).json({
       status: true,
       statusCode: 200,
       todo,
     })
  } 
}

export const todosController = new TodoController()
Enter fullscreen mode Exit fullscreen mode

The above code is very basic 2 controllers one for getAll and other for getById. Given that we have'nt setup our database connection yet we have a dummy todos list. At the end of our file we created an object of our controller class and exported it, you don't need to use classes, normal javascript functions will do.

Step Three: Add todo routes

Now let us setup a base router, under the src folder create a new folder called utils and under utils create a new file called BaseRouter.ts in this file paste the following code : -

import { Router } from 'express'

interface IRouter {
  router: Router;
  addRoutes(): void;
  returnApiEndpointRouter(): Router
}

export abstract class BaseRouter implements IRouter {
  router: Router

  constructor() {
     this.router = Router()
  }

  abstract addRoutes(): void

  abstract returnApiEndpointRouter(): Router;
}
Enter fullscreen mode Exit fullscreen mode

We created an abstract class, all our Route classes will extend this abstract class and when they do so they have to implement all the abstract methods like routes and returnApiEndpointRouter. Remember for abstract methods we only declare the methods using the abstract keyword we implement these methods in the child classes; those classes that will extend the BaseRouter abstract class.

Now under src/api/todos create a new file todos.router.ts and paste the following code : -

import { Router } from 'express'
import { BaseRouter } from '../../utils/BaseRouter'
import { todosController } from './todos.controller'

class TodosRouter extends BaseRouter {
 constructor() {
   super()
  }

  addRoutes(): void {
    this.router.get('/', todosController.getAllTodos)
    this.router.get('/:id', todosController.getTodoById)
  }

   returnApiEndpointRouter(): Router {
     this.addRoutes()
     return this.router
   }
}

export const todosRouter = new TodosRouter().returnApiEndpointRouter()
Enter fullscreen mode Exit fullscreen mode

We extended the BaseRouter abstract class implemented all the abstract methods, registered our routes in the addRoutes() method and finally created our router. The this.router is inherited from the parent BaseRouter abstract class.

Step Four: Register the todo router in our express app

Now in the server.ts file under the addRoutes() method paste the following code : -

private addRoutes() {
  this.app.use('/api/todos', todosRouter)
}
Enter fullscreen mode Exit fullscreen mode

And done we have added our route. Now from your terminal run npm run dev and check our todo routes by visiting -

  • http://localhost:8080/api/todos - get all todos.
  • http://localhost:8080/api/todos/2 - get the second todo.

Summary

There you go our basic routing and controller setup is completed. I hope you like the modularity and structure for our project. All the code for this tutorial can be found under the feat/setup-todo-routes branch here. In the next tutorial we will connect to a database until next time PEACE.

Top comments (0)