TypeScript Express tutorial #1. Middleware, routing, and controllers

Express JavaScript

This entry is part 1 of 15 in the TypeScript Express tutorial

Hello! In this new series, we build a RESTful application with TypeScript Express. The course is going to cover the fundamental concepts of the express framework and tools like MongoDB. Some basic knowledge of TypeScript would be useful, as we focus on Express here.

I will update the repository with the current state of the application as the course progresses. Feel free to give it a star! It is available at this address: mwanago/express-typescript. You can use it as a boilerplate if you would find it useful.

TypeScript Express tutorial #1

Express is a framework for Node.js used to build the backend for web applications. It is unopinionated, meaning that you can use it in a manner in which you see fit. In this tutorial, I present a way that works for me while working with the TypeScript Express.

Starting up the project

To get started we need to install necessary packages first using NPM.

If you would like to know more about NPM, check out Keeping your dependencies in order when using NPM

We start with an elementary tsconfig.json file:


To run our project, we need to add a script in our package.json:


As you can see, our app starts at the server.ts file in the src directory. Let’s start with the basics:


  • The express() function creates the Express application that we are going to interact with.
  • The get function, putting it simply, attaches a callback function to the specified path for the HTTP GET requests.
    • When someone makes a GET request for the specified path, the callback function runs.
    • the request and response objects represent the HTTP request and response properties
    • the response.send function causes the response to be sent to the client
  • the listen function makes the app listen for a connection on the specified port.
    • locally running   causes our application to be accessible at 

To test our application we use Postman. To install it, visit getpostman.com.

Let’s give it a try!

TypeScript Express



Middleware functions have access to the request and response objects.  It can attach to any place in the request-response cycle. A third argument that middleware receives is the next function. When called, the next middleware in the chain is executed. An example of a middleware is the get callback that handles the HTTP GET request that we’ve written above. It is a very specific middleware that executes on a particular case. They can also perform more generic tasks. Let’s create a very simple logger middleware that will log to console what requests were made.

In this example, as soon as someone sends the GET request to the /hello path, “GET /hello” will be printed in the console in which the app runs. In fact, it runs even when someone requests a page that you don’t have a handler for.

Thanks to calling next(), the control of the request can be passed further. If you create a middleware that neither ends the request-response cycle (for example by sending a response) or calls the next function, the request will not finish with a valid response.

There are a lot of ready to use middlewares that you can attach to your application and you will have plenty of chances to see some of them in this course. A crucial one is the body-parser. It parses the body of the incoming request and makes it available under the request.body property. In this example, we use the bodyParser.json middleware that parses the json data.

TypeScript Express Postman

The body was sent back to us thanks to running  . Without the body parser, the request.body property wouldn’t be accessible.

As we go further, we explain more advanced concepts connected to the middleware.


The app object has a set of functions that attach callbacks to HTTP requests performed to specified paths, just like the examples above with app.get and app.post. You can also attach callbacks to other HTTP methods like POSTPUT, PATCH and DELETE. You can look up a whole list of them in the documentation.

Another way to set up routing is to use the router object. Once you create a router object you can call the methods like get, put, patch and delete just like on the app object.

The only thing left that is required is to use the router.

As you can see by the usage of app.use, the router instance is just a middleware that you can attach to your application.

The addresses of the routes are a combination of paths provided for the app.use and the router.METHOD.

The code above results in creating a route /api/hello that responds with a text “Hello world!”.


The request object contains information about the HTTP request, such as headers, the request query string, and parameters.

It inherits from http.IncomingMessage.prototype and therefore contains its fields and methods, aside from adding new ones.

If you would like to know more about prototypes, check out Prototype. The big bro behind ES6 class

TypeScript Express Postman

We continue to go deeper into the request object as the course progresses.


The response object represents the HTTP response that the application sends when receiving an HTTP request.

It inherits from http.ServerResponse.prototype

Its the most important method is called send. It sends the HTTP response so that the client can receive it. The function accepts different types of data: strings, objects (Array included), or BuffersSend ends the response process with data, but you can also end it without any data using the end function.

The same as with the request, we dive more into the response object as we go.


A common way of structuring an Express application is called Model-View-Controller. Some of the key components of MVC are controllers. They contain the logic of the application and deal with handling client requests. Since this course covers TypeScript Express, we use classes. For the sake of readable code, I also create a class for the app instance itself.





The code above results in creating the route named /posts that responds on the GET and POST request, storing and displaying the list of posts. In the upcoming parts of the Typescript Express course, we continue to use controllers to structure our code.

The getAllPosts and createAPost are arrow functions because they access properties of an instance of the class. Since they are passed to the router and not called directly, the context changes.
You can achieve the same result by calling 

If you would like to know more about the this keyword, check out What is “this”? Arrow functions


In this article, we’ve grasped the very basics of building RESTful applications with TypeScript Express. It covered starting up a project, the use of middleware, routing and what are the request and response objects. The code that we write is structured in controllers and available in the repository. I hope that you will find it helpful. The repository will grow a lot in the upcoming future because there are more parts of the tutorial coming.

Series NavigationTypeScript Express tutorial #2. MongoDB, models and environment variables >>
Notify of
Newest Most Voted
Inline Feedbacks
View all comments
Alberto Montalesi
2 years ago

I’ve found a few typos. For example at the beginning you wrote tsconfig.js instead of .json and later on you wrote import Post from ‘./post.interface’; instead of import Post from ‘./posts.interface’; Just minor stuff in an overall great tutorial.

Predrag Stojadinovic
2 years ago
Reply to  Marcin Wanago

Alberto pointed out a typo, he did not comment on the naming choice…
In src/posts/posts.controller.ts you have:
import Post from ‘./post.interface’;

And it should be:
import Post from ‘./posts.interface’;

That’s all…

2 years ago

Correct me if i’m wrong, but:

const post: Post = request.body;

isn’t that line useless? i can send whatever i want and the controller will still push the request body into the existing posts array. i’m new to TS, so maybe i’m missing something, but i would expect some kind of an error if the incoming request body does not match the Post interface type. what’s the move here if i want a strict checking of the request?

2 years ago

Question: I’ve implemented this tutorial, but am having an issue…when I perform a GET, I am getting the posts that have been predefined. Good so far. Then I POST a new one and it regurgitates it back to me. Still Good. Then I perform a GET again and instead of only getting the predefined ones back, I’m now getting them, plus the new one. So my question is: controller classes aren’t re-instantiated per request? ( Sorry, very new to node and coming from an ASP.NET MVC background where “controllers” can handle per-request state. )

2 years ago

how can we integrate Winston logger in this?
please make a tutorial about logger implementation.

2 years ago

Why my IntelliSense is telling me that “Cannot find module ‘express'” and the same for body-parser? If I place the files in the root folder it works fine, but in src it behaves weirdly. When I run this server it works.

2 years ago
Reply to  Dmitriy

Hey, you would need to add the following to the tsconfig.json "moduleResolution": "node"
under the “compilerOptions”. I had the same problem, and when researching, it seems like typescript needs to know that we want to implement node modules – anyone correct me if that is wrong please.

At this point, thanks for the great article Marcin! Love it.


1 year ago
Reply to  Dustin

I had the same problem but it worked after this minor fix in the import statement.
Use this
import express from ‘express’;
import bodyParser from ‘body-parser’;

Instead of this
import * as express from ‘express’;
import * as bodyParser from ‘body-parser’;

2 years ago

this tutorial is the nice and the best

2 years ago

first of all great tutorial! Thanks for this!
I was wondering where we get the “express.Application” type from in the “app.ts” file at the time we declare “public app:”.

For anyone not so comfortable with TypeScript yet, this is coming from a “TypeScript Declaration File” which library authors can publish. Reference: http://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html

However, in order to get the proper type from it, I believe we need to install the express declaration file to our dev dependencies with npm install --save-dev @types/express

Could someone please confirm this?
At least before I hovered over “express.Application” I could see it’s type “any”, whereas after installing the declaration file, it now shows me “interface e.Application”


2 years ago

Hi Marcin,

perfect tutorial. But now I´m interested in how to implement e.g. Swagger.io into your existing project to have an api-documentation in place.
Maybe it would be perfect if you write a new blog with implementing swagger.io into it.


Stone Chen
Stone Chen
1 year ago

import express from 'express';

const app: express.Application = express();


I get “Property ‘use’ does not exist on type Application” error, and can not compile. If I change the app type to ‘any’, that would compile, but that defeats the purpose of the typing. Any ideas?

1 year ago

what is the type of a Controller should be? interface/class? so that all controllers follow the same structure, and also to use that type in app.ts instead of the ‘any’ type of ‘controllers’ argument

Stanley Huang
Stanley Huang
1 year ago

This is amazing, took me so long to find a tutorial on how to use Class from typescript to incorporate with Express. I believe you also cover how to do middleware as well . This is great, thank you.

Rapsan jani
1 year ago

This tutorial suggest me a basic & best way about MVC structure, Using this concept, I have developed MVC folder structure in Express with CRUD Example. So, Thanks for sharing..

3 months ago

Hi, thanks for sharing. If is send a POST-request to my application, i got a blank object as response. Is there a update or something else as reason that body-parser wont work? (i know this tutorial is 2 years old, but it is one of the best that i found for this topic)

3 months ago
Reply to  Yannik

Hey @Yannik

If you are getting in trouble with body-parser you can use express.json instead i.e


body-parser is deprecated.

I hope it helps

Happy coding :p