Nearly a month ago, the new version of TypeScript (2.5.2) was released. It introduced some new features, which reminded me of how beautiful Typescript is. That’s why I decided to describe how simple it is to write a web app with Express.js and TypeScript and why do I prefer to use them.
Express.js has some really powerful features which other frameworks do not have.
Definitely, it is the most mature Node framework that includes:
Express.js is really lightweight. I used many popular web frameworks like spring or spring bot in java, asp .NET in c# or laravel in PHP. They are great but too fat. They ship with too many dependencies.
The main question is: what kind of application will we build? We will create a simple web application using mentioned tech stack. It is worth to show, how easily with the use of Express.js we can develop properly secured app from scratch. You can do it without tons of dependencies and external libraries, where you have to trust the author’s code.
They also can be poorly written.
I assume that you have installed npm with Node, Mysql and your favourite code editor. I chose Visual Studio Code.
Let’s install the following dependencies.
At first, Express.js with Sequelize ORM and Mysql driver.
npm i -S express sequelize mysql2
As I said before, express.js is lightweight and plugin-oriented, which means that we need to install some plugins/middleware to handle everything beyond basic functionality.
npm i -S body-parser cookie-parser cors express-validator
We want to include user’s authentication into our app, so we need libraries for handling jwt tokens and password hashing.
npm i -S jsonwebtoken bcrypt
Finally, we need TypeScript with types.
npm i -D typescript @types/bcrypt @types/body-parser @types/cookie-parser @types/cors @types/es6-promise @types/express @types/express-validator @types/jsonwebtoken @types/node @types/sequelize
It is essential to mention npx. Notice that everything above was installed locally. For some reasons, it is better to install libraries in that way, but those installed globally are easier to run. Npx allows you to use packages installed locally as they are installed globally.
npm i -g npx
I’ve organised my folders in the following structure.
Generally, you only need tsconfig.json and index.ts files from here (for now), but it is nice to organise your folder correctly.
Our TypeScript config file specifies:
Fill index.ts like above, run
start npx tsc --watch with
node dist/index.js and type in your browser localhost:4001 and here it is. Comment lines define middlewares which are optional for now, but we need to enable cors and parsing json from post body, so better uncomment this.
Now, we have to connect with the database using Sequentlize.
Next, we should define the database with the required tables. For our app, the only table with users is mandatory.
I will create two similar routes in this app. First one is going to be unprotected. Access to the second route will be granted based on the jwt token. We need to define a database user model.
I’ve created four different user models. The last one is the most important. It allows us to query the database using Sequelize. Others are just types and names are self-descriptive.
Our app will contain four routes:
We need to create an appropriate router and service for them. We also need to define post body validator, which will be checking user credentials for example.
Here we have user service that contains methods for:
I do not want to expose the entire user model in the response body. In the code below you can see only id and email.
Our token guard middleware will check the existence of token in protected requests. If the token is not provided, it will return 403.
In the next step, we define rules of post body data validator for the appropriate route. Notice that you can specify them in your way. I prefer to expose as a plain js object.
Let’s define route logic and apply validator to the corresponding route.
Notice that the order of registering middleware is essential. Firstly, we define the unprotected route, then we register token guard middleware. It will be applied to any routes defined below.
It wasn’t so hard or time-consuming to write own authentication/authorisation middleware. It is an independent, easily extensible, and we developed it, so we know how it works. We don’t need to worry about magic code or unexpected behaviour while the app grows.
Thank you for your attention. If you have any questions, please leave a comment.
Other worthy reads