Using Prisma with Node.js in a Dockerized Environment
Prequirements
To complete this tutorial, you will need:
Using Prisma with Node.js in a Dockerized Environment
I will use Node.js
and Express. We will also use Prisma
to interact with the database.
Prisma is an open-source ORM (Object-Relational Mapping) tool for Node.js and TypeScript applications. It simplifies database access by providing an intuitive and type-safe way to interact with databases.
Create a folder called backend
at the root of the project.
mkdir -p <YOUR_PROJECT_FOLDER>/backend
Then open the folder in your terminal
and initialize a Node.js
project:
cd <YOUR_PROJECT_FOLDER>/backend
npm init -y
Build a FULL STACK Web app with Javascript API, Next.js, Node.js
, Express, Prisma,Postgres,Docker
Install the dependencies:
- express: to create the server
- prisma: to interact with the database
- @prisma/client: to generate the code to interact with the database
npm i express prisma @prisma/client
Initialize the prisma project:
npx prisma init
This initializes the prism project. We will use Prisma to interact with the database. Prisma will generate the code to interact with the database, so we don’t have to write it ourselves.
Open the file called .env
and replace the content with the following:
.env
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres?schema=public"
As a model for our project, we will use a ‘User’ with an id, a name, and an email. The id will be an autoincrementing integer, the name will be a string, and the email will also be a string.
Open the file /prisma/schema.prisma
and replace the content with the following:
<YOUR_PROJECT_FOLDER>/backend/prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
//User with id as int autoincrement, name as string, email as string
model User {
id Int @id @default(autoincrement())
name String
email String
}
Now create a file called index.js
inside the <YOUR_PROJECT_FOLDER>/backend
folder and add the following content:
<YOUR_PROJECT_FOLDER>/backend/index.js
const express = require('express');
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const app = express();
//use json
app.use(express.json());
//cors
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
//test api with error handling
app.get('/test', (req, res, next) => {
try {
res.status(200).json({ message: 'Success!' });
} catch (err) {
next(err);
}
});
//get all users
app.get('/users', async (req, res, next) => {
try {
const users = await prisma.user.findMany();
res.status(200).json(users);
} catch (err) {
next(err);
}
});
//get user by id
app.get('/users/:id', async (req, res, next) => {
try {
const user = await prisma.user.findUnique({
where: { id: Number(req.params.id) },
});
res.status(200).json(user);
} catch (err) {
next(err);
}
});
//create user
app.post('/users', async (req, res, next) => {
try {
const user = await prisma.user.create({
data: { ...req.body },
});
res.status(201).json(user);
} catch (err) {
next(err);
}
});
//update user
app.put('/users/:id', async (req, res, next) => {
try {
const user = await prisma.user.update({
where: { id: Number(req.params.id) },
data: { ...req.body },
});
res.status(200).json(user);
} catch (err) {
next(err);
}
});
//delete user
app.delete('/users/:id', async (req, res, next) => {
try {
const user = await prisma.user.delete({
where: { id: Number(req.params.id) },
});
res.status(200).json(user);
} catch (err) {
next(err);
}
});
//Start server
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Now you can generate the Prisma schema
npx prisma generate
Before we dockerize
the backend, let's test it.
Type in your terminal:
node index.js
Open your browser and go to http://localhost:4000/test
. You should see the message Success!.
But if we go on localhost:4000/users
, we actually see an error! This is because we don't have the schema in our database yet
We can proceed with the dockerization part, and we will solve this problem later.
Dockerize the backend
Let’s create 2 files, called .dockerignore
and backend.dockerfile
in the backend folder.
Open the file .dockerignore
and add the following content:
**/node_modules
Open the file <YOUR_PROJECT_FOLDER>/backend/backend.dockerfile
and add the following content:
<YOUR_PROJECT_FOLDER>/backend/backend.dockerfile
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY prisma ./prisma
RUN npx prisma generate
COPY . .
EXPOSE 4000
CMD ["node", "index.js"]
Let’s update the <YOUR_PROJECT_FOLDER>/compose.yaml
file in the project's root, adding the backend
service.
Create or updated compose.yaml
:
<YOUR_PROJECT_FOLDER>/compose.yaml
version: '3.9'
services:
backend:
container_name: backend
image: backend
build:
context: ./backend
dockerfile: backend.dockerfile
ports:
- "4000:4000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres?schema=public
depends_on:
- db
db:
container_name: pgdb
image: postgres:12
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata: {}
Build the backend image:
docker compose build
Start the backend container:
docker compose up -d backend
Check if the container is running:
docker ps -a
Something interesting before we proceed or make any http requests.
docker exec -it pgdb psql -U postgres
\dt
And we should see no relations.
Now type
docker exec -it backend npx prisma migrate dev --name init
docker exec -it pgdb psql -U postgres
\dt
And we should see the table User in the database. Of course it’s still empy, but Prisma has created it for us. Cool!
Testing
I will add users in 3 different ways.
- one user using Prisma Studio
- one user using Postman
- one user using psql
Create a user using Prism Studio
Open a new terminal and type:
cd <YOUR_PROJECT_FOLDER>/backend/
npx prisma studio
This will open Prisma Studio in your browser at http://localhost:5555
(Note: we are not using Docker to run Prisma Studio, we are running it directly on our machine).
Add a record: Aung Thu Oo
and example@gmail.com
hit Save 1 change
. You can leave Prisma Studio open in a tab, we will use it later.
If we make an http request to http://localhost:4000/users
we should see 1 user (the one we just created using Prisma Studio).
[{
"id" : "1",
"name": "Aung Thu Oo",
"email": "example@gmail.com"
}]
Now let’s add another user using Postman
(or any other tool you like).
If we check localhost:4000/users
we should see users now:
We can also check again on Prisma Studio, to check the consistency of our operations.
Insert user from psql
Let’s insert another user using psql
.
cd <YOUR_PROJECT_FOLDER>/
docker exec -it pgdb psql -U postgres
\dt
Let’s insert a new user manually using psql
(don't do this in production, it's just for testing purposes!).
insert into "User" (name, email) values ('ATO developer', 'atodev@gmail.com');
select * from "User";
Let’s check again on Prisma Studio
, and we should see 3 users now:
#daily_dev_note