Developing an Express Application Using TypeScript

itachiuchiha

Itachi Uchiha

Posted on November 3, 2019

Developing an Express Application Using TypeScript

This post was first published on my blog.

Recently, I was working on TypeScript. I asked a question about TypeScript. Dev users helped me.

In this post, I'll show you how to create an express application using TypeScript.

Before you start, I'm so sorry for my grammar mistakes.

Express Framework

As you know, Express is a NodeJS web framework that works on the server.

Installation of Dependencies

npm i express pug ts-node typescript @types/express @types/node
Enter fullscreen mode Exit fullscreen mode

These are dependencies.

Edit package.json and tsconfig.json files

The scripts section in the package.json will be like that;

"scripts": {
    "dev": "ts-node src/server.ts",
    "start": "ts-node dist/server.js",
    "build": "tsc -p ."
}
Enter fullscreen mode Exit fullscreen mode

I'll be able to run the dev version of this application using the npm run dev command.

My tsconfig.json file will be like that;

{
    "compilerOptions": {
        "sourceMap": true,
        "target": "es6",
        "module": "commonjs",
        "outDir": "./dist",
        "baseUrl": "./src"
    },
    "include": [
        "src/**/*.ts"
    ],
    "exclude": [
        "node_modules"
    ]
}
Enter fullscreen mode Exit fullscreen mode

Project Structure

This is our project structure;

- dist
- node_modules
- public
- src
- views
package.json
tsconfig.json
Enter fullscreen mode Exit fullscreen mode

By the way, public and views folders are not necessary if you don’t need UI in your project. (For example API backend). The project will develop under the src folder.

- controllers
- interfaces
- middleware
app.ts
server.ts
Enter fullscreen mode Exit fullscreen mode

The controllers folder will have route controllers and their interface files. The interfaces folder will have interface files. The middleware folder will have our middlewares.

Let's look at the app.ts and server.ts files

Application File src/(app.ts)

My application file is like that;

import * as express from 'express'
import { Application } from 'express'

class App {
    public app: Application
    public port: number

    constructor(appInit: { port: number; middleWares: any; controllers: any; }) {
        this.app = express()
        this.port = appInit.port

        this.middlewares(appInit.middleWares)
        this.routes(appInit.controllers)
        this.assets()
        this.template()
    }

    private middlewares(middleWares: { forEach: (arg0: (middleWare: any) => void) => void; }) {
        middleWares.forEach(middleWare => {
            this.app.use(middleWare)
        })
    }

    private routes(controllers: { forEach: (arg0: (controller: any) => void) => void; }) {
        controllers.forEach(controller => {
            this.app.use('/', controller.router)
        })
    }

    private assets() {
        this.app.use(express.static('public'))
        this.app.use(express.static('views'))
    }

    private template() {
        this.app.set('view engine', 'pug')
    }

    public listen() {
        this.app.listen(this.port, () => {
            console.log(`App listening on the http://localhost:${this.port}`)
        })
    }
}

export default App
Enter fullscreen mode Exit fullscreen mode

As you can see, the constructor expects three parameters. In this logic, port and controller parameters should be required but I wasn't sure about it. I've also init the assets and templates in case you use the UI in your project.

Server File src/(server.ts)

My server file is like that;

import App from './app'

import * as bodyParser from 'body-parser'
import loggerMiddleware from './middleware/logger'

import PostsController from './controllers/posts/posts.controller'
import HomeController from './controllers/home/home.controller'

const app = new App({
    port: 5000,
    controllers: [
        new HomeController(),
        new PostsController()
    ],
    middleWares: [
        bodyParser.json(),
        bodyParser.urlencoded({ extended: true }),
        loggerMiddleware
    ]
})

app.listen()
Enter fullscreen mode Exit fullscreen mode

In this file, we've imported our App class. We passed three parameters. The first one port number. Our app will run on port 5000.

The second one is the controllers parameter. Our controller classes will be here with the new keyword.

And the last one middleWares. If you're using bodyParser or similar plugins you can use the middleWares.

Our Simple Middleware (middleware/logger.ts)

import { Request, Response } from 'express'

const loggerMiddleware = (req: Request, resp: Response, next) => {

    console.log('Request logged:', req.method, req.path)
    next()
}

export default loggerMiddleware
Enter fullscreen mode Exit fullscreen mode

This is a simple HTTP logger. It shows the HTTP verb and its path.

IControlerBase (interfaces/IControllerBase.interface.ts)

I thought so that every controller has to implement this interface.

interface IControllerBase {
    initRoutes(): any
}

export default IControllerBase
Enter fullscreen mode Exit fullscreen mode

Our First Controller (controllers/home.controller.ts)

HomeController will be like that;

import * as express from 'express'
import { Request, Response } from 'express'
import IControllerBase from 'interfaces/IControllerBase.interface'

class HomeController implements IControllerBase {
    public path = '/'
    public router = express.Router()

    constructor() {
        this.initRoutes()
    }

    public initRoutes() {
        this.router.get('/', this.index)
    }

    index = (req: Request, res: Response) => {

        const users = [
            {
                id: 1,
                name: 'Ali'
            },
            {
                id: 2,
                name: 'Can'
            },
            {
                id: 3,
                name: 'Ahmet'
            }
        ]

        res.render('home/index', { users })
    }
}

export default HomeController
Enter fullscreen mode Exit fullscreen mode

We've implemented the IControllerBase. So, we must follow its rules. In this example controller file, we're assuming that we have data from the database server. I sent this data to the (home/index.pug) file. This file is located under the views folder.

<!DOCTYPE html>
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        meta(http-equiv="X-UA-Compatible", content="ie=edge")
        title Document
    body
        each user, index in users
            h2(onclick=`alert(${index})`)= user.name
Enter fullscreen mode Exit fullscreen mode

This is our pug file. We've also implemented the initRoutes method. Because the boss(IControllerBase) wants that.

Let's start the app

npm run dev
Enter fullscreen mode Exit fullscreen mode

With this command, we will be able to run our application. Our application works on http://localhost:5000.

Developing an Express Application Using TypeScript

You can also check the posts folder. In this project, you can use TypeORM or Sequelize.

You can find this project on GitHub: https://github.com/aligoren/express-typescript-test

Conclusion

I really loved to use TypeScript. Before this work, I never had an idea about how TypeScript works.

Thanks for reading.

💖 💪 🙅 🚩
itachiuchiha
Itachi Uchiha

Posted on November 3, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related