Introduction
In this tutorial, we will be building a simple authentication system using NodeJS, TypeScript, Prisma, and Postgres.
User Authentication is a critical part of every application development and in this tutorial, we will be seeing how to implement one with NodeJS. The code for this project is located here
Before we begin let's go over the pieces we will be using and how they fit.
NodeJS: This is a JavaScript runtime built on Chrome's V8 JavaScript engine. To simply put, with NodeJS we can run JavaScript on the server. I explain this better in my other article.
TypeScript: This is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale. Have you seen the popular JavaScript error "cannot read property...", simply put, TypeScript helps reduce those errors
Prisma: A NodeJS and TypeScript ORM that helps us interact better with our Databases. currently supports, SQL(MySQL, Postgres e.t.c) and NoSQL Databases(MongoDB)
Postgres: An SQL Database for storing data.
Let's start by initializing a node project in the directory of our choice. Simply run the command below;
npm init -y
The above command will generate a package.json file. I will assume you know what the package.json file means but on a high level, it is where all the dependencies for our project will be stored.
Talking about dependencies, run the command below to install dependencies.
On a high level, we have two types of dependencies captured in our package.json file as "devDependencies" and "dependencies".
On a high level, devDependencies are modules that are needed during development while dependencies are needed during runtime.
To install a package as devDependency, we add the "--save-dev" or "-D" flag when we are installing our packages.
Previously we use to install dependencies with the "--save" flag but with the latest node version, you can install your packages directly without need of "--save" flag.
For this project, we will need to install the following packages as devDependencies; prisma, typescript, ts-node, @types/node, @types/express, nodemon
So, run "npm install prisma typescript ts-node @types/node --save-dev"
npm install prisma typescript ts-node @types/node --save-dev
Also, we will be installing the following packages as dependencies: express
By now, you already know we will be using typescript for this project. Please ensure you install typescript locally on your PC.
We now have to generate a tsconfig file, you can run "tsc --init"
tsc --init
But, I will be using the tsconfig file from the Prisma docs. you can use that too. To use it, simply create a tsconfig.json file in the root of your directory and paste the code below into it;
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext"],
"esModuleInterop": true
}
}
Now lets's get prisma setup
on your terminal, run the command "npx prisma init".
Also, I will be assuming that we have NodeJs installed locally on our laptops.
The above command will generate a directory called "prisma" and a .env file at the root of our project. The .env file is where our database connection string is, we can also add other environment variables there.
The prisma directory contains the "schema.prisma" file. This is where we will define our model.
For this project, we will be using Postgres. You can add the connection string on the .env file using a local Postgres db or hosted on Heroku or supabase.
We will use express-validator to validate our request body. On a high level, it works as a middleware in our express app. kindly see code for more insight.
Run the command "npm install express-validator"
Also, we will be performing some production-grade error handling. We may not explain all of that in this article and I don't want this getting this article going beyond one(1) part. I'd do my best to comment on the code and you can download it from the repo link.
On the error handling, it may be an over-kill for this simple app but I had to share it as that's what I use for most of my projects.
Kindly note, you have to install the package "express-async-errors"; with this package, we can throw errors without necessarily using the next function.
Let's get back to Prisma: Recall that prisma is an ORM that helps us interact with our DBs in the easiest possible way. Trust me, you'd love it when you try it.
Firstly, let's set up our DB. For me, I am using the local Postgres DB on my PC. You can use Heroku, Supabase, or install Postgres locally on your PC.
After setting up your DB, kindly update the .env file with the right connection string then, you can continue.
model User {
id String @id @default(uuid())
email String @unique
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
We now run the command "npx prisma migrate dev --name init"
npx prisma migrate dev --name init
You can actually name your migrations anything but for this, we would adopt the convention used on the Prisma docs. You can read this up on the Prisma documentation.
To interact with our DB, we have to install the Prisma client.
Run the command "npm install @prisma/client" on your terminal.
npm install @prisma/client
We will create a client.ts file in our src folder and with this client.ts file, we can query our DB using the Prisma client instance.
Also, if any method is not clear for you, you can look up the documentation for a better understanding as there is little we can cover in this article.
You can view your DB using the command "npx prisma studio", isn't that amazing?
npx prisma studio
So now, we will install JSON web token(JWT) to help generate tokens. kindly run the following in your terminal
npm install jsonwebtoken @types/jsonwebtoken
The codebase also shows how passwords are hashed before they are being saved on the Database.
So, this is getting long and I aimed this article at providing an easy template for anyone that intends to build user authentication APIs using TypeScript.
You can find the complete code here.
Also, like I stated on the readme.md file, you can choose to design your own model using any DB of your choice.
I hope that when you go through the code, all we have written will make sense to you.
Thank you for reading.