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.
Table of Contents
- 1. Prerequisites
- 2. Step by Step Guide
- 3. Conclusion
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 by Step Guide
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.
Tech Tales Team
Published on
Rest API resting when there is no work
Tutor Juliet
Published on
Beat my gif!
Tech Wizard
Published on
Let me Rest
Tutor Juliet
Published on
why is it called rest api, is it resting?😂
the don
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"
Tech Wizard
• Oct 30, 2024