API with NestJS #32. Introduction to Prisma with PostgreSQL

JavaScript NestJS TypeScript

This entry is part 32 of 177 in the API with NestJS

So far, in this series, we’ve been using TypeORM to manage our data and connect to our Postgres database. In this article, we look into Prisma, which is a capable alternative.

With Prisma, we describe our data using a Prisma schema file. It uses its own data modeling language and acts as a single source of truth. This differs from traditional ORMs that provide an object-oriented way of working with the database.

Every time we make changes to the schema file, we need to generate the Prisma client. In this process, Prisma parses our schema and creates a client along with all the TypeScript typings. This means that we no longer map SQL tables to model classes through the TypeScript code manually.

The Prisma client is a set of Node.js functions that we can call from within our code. Under the hood, the client connects to a query engine written in Rust.

Although it is possible to migrate from TypeORM to Prisma, in this aricle we set up our project from scratch.

You can find all of the code from this article in this repository.

Setting up PostgreSQL and Prisma

In this series, we are using PostgreSQL. The most straightforward way to add Postgres to our project is to do it with docker. In the second part of this series, we set up PostgreSQL with TypeORM. Let’s reuse the docker-compose file provided there:

docker-compose.yml

We also need to create a file that contains environment variables for our docker container.

docker.env

To start using Prisma, we first need to install it.

Once that’s done, we can start using the Prisma CLI. The first thing we want to do is to initialize our configuration.

Doing the above creates two files for us:

  • : contains the database schema and specifies the connection with the database
  • : contains environment variables

We need to modify the above file to adjust to the contents of :

.env

Within the file, we have access to our environment variables. Let’s use the variable to set up the connection.

schema.prisma

Installing and using the Prisma Client

To start using the Prisma Client, we first need to install it.

Let’s create a class that initializes the .

prisma.service.ts

We also need to create a module that exports the above service.

prisma.module.ts

Managing basic tables with Prisma Client and Prisma Migrate

When we want to modify the structure of our database, we should create a migration. It consists of a SQL script that is supposed to make the necessary changes. Although we could write it by hand, Prisma can do it for us with the Prisma Migrate tool.

First, let’s define a simple model in our schema.

schema.prisma

Above, we define the basic set of fields for our model. Above we use just the and types, but there are quite a few to choose from.

Aside from defining fields, we also can define attributes. Their job is to modify the behavior of fields or models.

With the attribute, we define a default value for a field. When using it, we have a set of functions to choose from. Above, we use to create a sequence of integers.

In our model, we also use the attribute. Thanks to that, our field becomes the primary key.

Once we’ve got our model, we can create our migration.

Above we use the flag, because the Prisma Migrate tool is still in preview. It means that the functionality was validated, but there might be small bugs.

Aside from creating a file with the SQL script, running the above command also changed our database.

Using Prisma Client to manage the data

Once all of the above is done, we can start using the Prisma Client. Let’s start with the basics.

posts.service.ts

The property was created when we generated our Prisma Client based on our schema and it recognizes the properties our entity has.

The method without any arguments returns all entities from the queried collection.

posts.service.ts

Above, we use the method that aims to find a single entity from our collection. We need to provide it with the property to narrow down the scope of our search.

We can also use the property with the method.

If the method returns , we can assume that it didn’t find the entity. If that’s the case, we can throw an exception.

postNotFound.exception.ts

Doing the above results in responding with the 404 Not Found status code.

If you want to know more about error handling, check out API with NestJS #4. Error handling and data validation

posts.service.ts

Above, we use the method to save a new entity in the database. The class describes all of the properties along with data validation.

createPost.dto.ts

If you want to read about validation, check out API with NestJS #4. Error handling and data validation

posts.service.ts

Above, we use the method to modify an entity. It is worth noting that we ignore the property so that the users can’t change it.

updatePost.dto.ts

We need to use the to see what errors have been thrown. To do that properly, we can create an enum based on the official documentation.

prismaError.ts

posts.service.ts

Above with the method, we do a very similar thing in terms of error handling.

Once we’ve got our service ready, we can create a controller that uses it.

posts.controller.ts

It is worth noting that above we use the that transforms ids from strings to numbers.

findOneParams.ts

Using multiple schema files

Putting all of our schema definitions into a single file might make it difficult to maintain. Unfortunately, Prisma currently does not support multiple schema files.

To deal with this issue, we can create a simple bash script that merges multiple schemas into one.

package.json

Running merges all files into the directory. It traverses through all of the subdirectories of .

The command is available in Linux, Mac, and Windows Power Shell

We can also put the file into so that we don’t have multiple sources of truth.

.gitignore

Doing the above allows us to keep separate schema files for specific modules. Let’s split our existing schema into multiple files:

baseSchema.prisma

postSchema.prisma

We end up with the following file structure:

Summary

In this article, we’ve learned the basics of Prisma. We’ve got to know its main principles and we’ve created a simple CRUD API with it. To do that, we’ve had to get familiar with the basics of the data modeling language Prisma uses. It also required us to learn about the basics of the Prisma Migrate tool. There is still quite a lot to learn about Prisma, so stay tuned!

Series Navigation<< API with NestJS #31. Two-factor authenticationAPI with NestJS #33. Managing PostgreSQL relationships with Prisma >>
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Fan
Fan
3 years ago

More Prisma articles please! I’d like to know more advanced features

Jyoti Satya
Jyoti Satya
3 years ago

Hi Mr Wanago,

I want to redesign my backend API service and make use of DI or existing framework so choose to start with Nestjs and following your series of article on Nestjs, it seems very promising and I am at 8th article.
I was earlier using express with bookshelf ORM.

Just want to know which ORM should I start to explore:TypeORM or Prisma as you have used both: what should I follow and why?