So, you have a brilliant idea for a web application. It’s going to be the next big thing, and you are super-excited about it. Maybe you have already started building the perfect React/Angular UI for your app.
Now comes storing the data. Naturally, you select PostgreSQL. After all, it is the most advanced Relational Database Management System (RDBMS) in the world, with its object-oriented features and extensibility. But RDBMSs can be slow for frequently used data and caching, so you decide to add Redis, the in-memory cache, to decrease data access latency and ease the load off your relational data store.
That’s it. You have a perfect server waiting to be built. And while the initial process of getting it up and running can get arduous, you have come to the right place. This blog is going to guide you through the initial setup process.
I am assuming you have a non-root user with sudo privileges running on Ubuntu 16.04. Before we start, please make sure you have the following:
- NPM (~v6.9.0) and Node.js (~v10.16.0) – You can use this How to Install Node.js on Ubuntu 16.04
- Redis – How to install Redis on Ubuntu 16.04
- PostgreSQL – How to install PostgreSQL on Ubuntu 16.04
Of course, MacOS or Windows would do fine too for this tutorial, but to use them, please find appropriate installation guides on the Internet before moving forward.
If you don’t want to go through the steps below, you can check out my GitHub Repo typescript-express-server and use it as your application skeleton. It has been set up with default configurations, which you can change later. Nevertheless, I strongly recommend going through this guide to further your understanding of the project files and configuration nuances.
Initializing Server (Express with TypeScript)
Setting up an Express Application with TypeScript can be done in three steps:
Initialize project using NPM
Create a folder and run:
This will ask you a couple of project-specific questions, like name and version, and will create a package.json file, which may look like this:
This manifest file will contain all the metadata of your project, like module dependencies, configs, and scripts. For more information, check out this very good read about the basics of package.json.
Setting up TypeScript Configuration (tsconfig.json)
This file needs to be created in the root of a TypeScript project. During development, TypeScript provides us with the convenience of running the code directly from the .ts extension files. But during production, since Node.js only understands JS, the entire TS files need to be transpiled to JS. Some of the options are: include - specifies the files to be included, exclude - the files to exclude, and the compiler options: outFIle and moduleResolution.
First, we need to install some TypeScript specific modules:
This is the tsconfig.json file with some default configurations:
For a detailed reference, checkout tsconfig.json.
Run this command:
Create a .eslintrc file in the project root and use the following starter configuration:
Lastly, add a lint script to package.json:
Now, you can run the command below to lint your codebase for lint errors:
ESLint has ample rules to enforce standards in your code. Please look them up at Eslint with TypeScript.
Finally, we need to install Express, which is as simple as running this command:
You need a server file (src/Server.ts), which you can create like this:
You will also need src/index.ts that will be the entry point for your application:
Many Express servers are configured to swallow all errors by configuring an Uncaught Exception handler, which in my opinion, is bad news. The best thing to do is to allow the application to crash and restart. Uncaught Exceptions in Node.js is a good read regarding this.
Nonetheless, we are going to configure an error handler that will print errors and send a BadRequest response when an invalid HTTP request comes your API’s way.
In the src/Server.ts, add this:
Kudos! You have a basic Express server set up. Fire it up by running:
Connecting with the Database Store using TypeORM
Create an ormconfig.json file in your project root with the following configuration:
Create a src/db.ts file that will initialize the database connection:
TypeORM Entities are classes that represent the data models in our application. We are going to build a User Entity (which application doesn’t have a user, duh!) like this in src/entities/User.ts:
Then, add these lines to src/index.ts:
You will need the env variables, like TYPEORM_CONNECTION, TYPEORM_HOST, and TYPEORM_USERNAME, with your postgres db’s connection params. Please check TypeORMs documentation for more details.
We will use Tedis, the TypeScript wrapper for Redis in our server:
Add these lines to src/db.ts:
And these lines to src/index.ts:
Now, your application code can use the Redis cache using the client created above.
Logging is pivotal to an application because it gives us a real-time view of the state of our application. For development, we are going to install the Morgan Request Logger, a library that logs HTTP requests params. It comes really handy for debugging.
And include this in src/Server.ts:
Winston can be used as the system-wide universal logger. Install it like this:
Then, add a src/shared/Logger.js file:
Now, you can use this logger from anywhere in the code, be it for error logging in your API methods or for debugging purposes:
Creating your First API Service
This is the moment you have been waiting for: creating your first API service for your application, the crux of the functionality that will define your web application.
This API service is a simple GET request handler, which returns all the users in your database. You should have src/Users.ts, which can look like:
Voila! Your API service is ready. Fire up your server, and then use Postman to make requests to your API and see the magic happen.
You can also add other API services for fetching a user by ID, deleting a user, creating a user, and updating a user. I will not discuss them here to keep this blog short. You can find these in the Github repository I mentioned in the beginning.
Deploying your Server to Production
What we have been doing has been in the development phase. Now, we need to take this to production. You just need to have a <project-root>/build.js </project-root>script that will create a <project-root>/dist</project-root> folder and transpile all the TypeScript files that you have written. It can look like this:
Then, add this line to your <project-root>/package.json</project-root>:
Now, you can use:
Doing so builds up the <project-root>/dist</project-root> folder and transpiles your code. You can deploy this folder to your deployment environment and run it to start your production server:
Note: You will need to do some additional setting up of your Nginx or AWS Virtual Machine to complete your deployment, which is beyond the scope of this blog.
Congratulations. You have made it through this tutorial that guided you through the process of setting up a web server. But this is just the beginning, and there is no end to the improvements and optimizations that you can add to your server to make it better and sturdier. And you will continue to discover them in your journey of developing your web application. Some of the key points that I want to mention are:
Your Web server will be operated in multiple environments, such as development, testing, and production. Some of the vital configurations like AWS credentials and DB passwords are sensitive information, and managing them per environment is key to your development and deployment cycle. I strongly recommend using libraries like Dotenv and keeping your env configurations separate in your codebase. You can look up typescript-express-server for this.
Software developers nowadays swear by this tool. It’s proved to be a godsend for API documentation and keeping APIs in confirmation with the OpenAPI standard. On top of that, it also does API requests validation according to your API specifications. I strongly recommend you configure this in your web server.
Writing API tests and unit tests can be a crucial part of web application development as it exposes possible gaps in your systems. You can use Superagent, the lightweight REST API, to test your APIs for all possible requests and response scenarios. Please look up the src/spec in typescript-express-server about how to use it. You can also use Postman for API Testing Automation. For most of the services that you write, you should make sure to add unit tests for each of those using Jest.
- Node.js production checklist
- Node.js production best practices
- Production best practices: performance and reliability