prisma tutorial
user profile avatar
Tech Wizard

Published on • 🕑5 min read

Building A REST API with Prisma, NodeJS and PostgreSQL

1likes0

Blog views66

Listen to this blog

I once shared that I have migrated my database from Active Record using ruby on rails to a Prisma ORM and Node Js server powered by NextJS. This tutorial will create a simple API for Tesla vehicles to help you get started. Prisma is a powerful database toolkit that simplifies working with databases by providing a modern, type-safe query builder.

We'll cover the following Prisma essentials:

  1. Connecting Prisma with a Database
  2. Setting Up Prisma Migrations
  3. Seeding the Database
  4. Implementing CRUD Operations

Prerequisites

Before starting, ensure you have the following:

  • Node.js installed (Version 14 or higher)
  • A PostgreSQL database (you can create a free database with Vercel or Neon DB)

Step 1: Setting Up Your Node.js Project

The first step is to initialize a new NodeJS project in the terminal. This project will be the foundation for the REST API you will build in this tutorial. To do this, you must first create a folder and a typescript project.

mkdir tesla-api
cd tesla-api
npm init -y

After creating a new NodeJS project, we need to install other prerequisites such as typescript and Prisma CLI.

npm install typescript ts-node @types/node --save-dev
npm install express prisma @prisma/client

Lastly, we need to add a tsconfig.json file to make sure Typescript works correctly. You can create the file manually or use nano tsconfig.json and add the following code.

{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "dist",
    "strict": true,
    "lib": ["esnext"],
    "esModuleInterop": true
  }
}

Step 2 — Setting Up Prisma with PostgreSQL

The second step is to initialize Prisma and create our vehicle model to map with the database. We first need to add our database URL to the .env file so that Prisma knows how to connect with the database.

nano .env

Now update the .env file to add your database url from Vercel, NeonDB, or another database provider. If you are using Ubuntu, you can also run PostgreSQL locally using pgadmin. If you are on a pooled database you also need a NON-POOLING url to be used for seeding.

//tesla-api/.env
DATABASE_URL="postgresql://johndoe:your_password@localhost:5432/my-blog?schema=public"
NON_POOLING_DATABASE_URL="postgresql://johndoe:your_password@localhost:5432/my-blog?schema=public"

Make sure to change the database credentials to the ones you specified in your hosted database or localhost database. Once you’re done, save and exit the file and initialize Prisma by running. npx prisma init.

npx prisma init
Output
✔ Your Prisma schema was created at prisma/schema.prisma.
  You can now open it in your favorite editor.

Step 3 — Defining Your Data Model and Creating Database Tables

Now that your project is initialized, it's time to define your data model. Navigate to the prisma/schema.prisma file in your project directory. Here, you'll define your database schema using Prisma's intuitive schema language.

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("NON_POOLING_DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Vehicle {
  id        Int     @id @default(autoincrement())
  model     String
  price     Float
  picture   String
  year      Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

We are defining just one model for the Vehicle with fields for model, price, picture, and year, but you can add a user model if you like. Save the changes and close the file.

With these models in place, you can now create the corresponding tables in the database using Prisma Migrate. In your terminal, run the following command:

npx prisma migrate dev --name init

This command generates a new migration file based on your data model changes. The SQL migration file in the prisma/migrations/20241209084626_init/migration.sql directory has the following statements that were executed against the database.

Step 5: Generating a Prisma client

It is often a good practice to create a global Prisma client to prevent recreating a new instance every time. To do this, we initialize Prisma Client using npx prisma generate and create a new folder where we declare a Prisma client and export the client for use in other files.

npx prisma generate

Now create a file named prisma.ts under the Prisma folder and add the following code:

//prisma.prisma.ts
import { PrismaClient } from "@prisma/client";
declare global {
    let prisma: PrismaClient | undefined;
  }
  const globalForPrisma = global as typeof global & { prisma?: PrismaClient };
  let prisma: PrismaClient;
  if (!globalForPrisma.prisma) {
    globalForPrisma.prisma = new PrismaClient();
  }
  prisma = globalForPrisma.prisma;
  export default prisma;

Step 6: Seeding the Database

Prisma allows us to seed the database if we have some seed data. To seed your database, you need to add a seed.ts file and add our seed data. In a larger project, you might need to edit the package.json to add a seed script.

//prisma/seed.js
import prisma from "../prisma/prisma"
async function main() {
  await prisma.vehicle.createMany({
    data: [
      { model: 'Tesla Model S', price: '51885.17', picture: 'https://static-assets.tesla.com/configurator/compositor?&options=$MT337,$PPSW,$W40B,$IBB1&view=STUD_FRONT34&model=m3&size=1920&bkba_opt=2&version=v0028d202109300916&crop=0,0,0,0&version=v0028d202109300916', year: 2012 },
      { model: 'Tesla Model 3', price: '100990', picture: 'https://static-assets.tesla.com/configurator/compositor?&options=$MTS10,$PPSW,$WS90,$IBE00&view=FRONT34&model=ms&size=1920&bkba_opt=2&version=v0028d202109300916&crop=0,0,0,0&version=v0028d202109300916', year: 2017 },
      { model: 'Tesla Model X', price: '120990', picture: 'https://static-assets.tesla.com/configurator/compositor?&options=$MTX10,$PPSW,$WX00,$IBE00&view=FRONT34&model=mx&size=1920&bkba_opt=2&version=v0028d202109300916&crop=0,0,0,0&version=v0028d202109300916', year: 2015 },
      { model: 'Tesla Model Y', price: '65000', picture: 'https://static-assets.tesla.com/configurator/compositor?&options=$MTY07,$PPSW,$WY19B,$INPB0&view=FRONT34&model=my&size=1920&bkba_opt=2&version=v0028d202109300916&crop=0,0,0,0&version=v0028d202109300916', year: 2020 }
    ]
  });
}

main()
  .then(() => {
    console.log('Database seeded');
  })
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

Next, run the seed script in the terminal by running the command:

node prisma/seed.js

Step 7: Create CRUD Operations

The next step is to initiate a ExpressJs server to interact with the database and perform CRUD operations.

First, create a index.ts file to add our server code.

nano src/index.ts

In the src/index.ts file, add the following code to create the API routes.

import express from "express";
import prisma from "../prisma/prisma"
const app = express();
app.use(express.json());
// Get all vehicles
app.get('/vehicles', async (req, res) => {
  const vehicles = await prisma.vehicle.findMany();
  res.json(vehicles);
});
// Get a vehicle by ID
app.get('/vehicles/:id', async (req, res) => {
  const { id } = req.params;
  const vehicle = await prisma.vehicle.findUnique({
    where: { id: parseInt(id) },
  });
  res.json(vehicle);
});
// Create a new vehicle
app.post('/vehicles', async (req, res) => {
  const { model, price, picture, year } = req.body;
  const newVehicle = await prisma.vehicle.create({
    data: { model, price, picture, year },
  });
  res.json(newVehicle);
});
// Update a vehicle
app.put('/vehicles/:id', async (req, res) => {
  const { id } = req.params;
  const { model, price, picture, year } = req.body;
  const updatedVehicle = await prisma.vehicle.update({
    where: { id: parseInt(id) },
    data: { model, price, picture, year },
  });
  res.json(updatedVehicle);
});
// Delete a vehicle
app.delete('/vehicles/:id', async (req, res) => {
  const { id } = req.params;
  await prisma.vehicle.delete({
    where: { id: parseInt(id) },
  });
  res.sendStatus(204);
});
// Start the server
app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

Test the server by running the following command

npx ts-node src/index.ts
or
node src/index.ts

You can modify the routes to add try catch blocks for error handling. You can also edit the package.json file to make it easier to run the server by adding a run script. Update the package.json file to add the following code.

"scripts": {
  "build": "tsc",
  "start": "node dist/index.js",
  "dev": "ts-node src/index.ts"
}

Now you can start the development server using npm as follows:

npm run dev

Conclusion

In this article, you created a REST API server with several different routes to create, read, update, and delete user and post data for a sample blogging application. Inside the API routes, you use the Prisma Client to send the respective queries to your database.

As next steps, you can implement additional API routes or extend your database schema using Prisma Migrate. Visit the Prisma documentation to learn about different aspects of Prisma and explore some ready-to-run example projects using tools such as GraphQL or grPC APIs in the prisma-examples repository.

 

Like what you see? Share with a Friend

1 Comments

0 Likes

Comments (1)

sort comments

Before you comment please read our community guidelines


Please Login or Register to comment

user profile avatar

the don

online

Published on

Thank you for this informative tutorial. One point to note is that we need to restart the server each time we make changes. We can avoid this by installing ts-node-dev and changing the scripts or using nodemon.

      |  npm install ts-node-dev --save-dev

      | "dev": "ts-node-dev --respawn src/index.ts"