A Simple REST API with Prisma, Part 2: The Server

This series covers building a simple REST API using the Prisma ORM and Postgresql. Part one covered how to get a Prisma schema from your Postgresql database, and used information from a national plant database as an example. Next up, I’ll explain how to use this Prisma client in our express server.

Setting up our Data Access Layer

Let’s create a PostgresService.ts file where our Prisma ORM will read and write to our database. We will need to import the PrismaClient and instantiate it.

import { PrismaClient } from ‘@prisma/client’;
const prisma = new PrismaClient();

Then, we will create a class called PostgresService with a simple get method:

export class PostgresService {
async getPlantsByCommonName(name: string): Promise {
return await prisma.usdaplants
.findMany({
where: {
common_name: name,
},
})
.then((res) => this.stringifyData(res));
}
}

Here, we take in the name from the client’s request and format its response before giving it back to the client.

Creating Our Routes

Once we have our data access layer, we need to create our routes. In routes/index.ts, it will look like this:

import express from 'express';
import { PostgresService } from '../services/PostgresService';

export const router = express.Router();
const db = new PostgresService();

router.get('/', (_req, res) => {
res.send(
'Make a request. \n e.g http://localhost:3000/plants/{name}'
);
});
router.get('/plants/:name', async (req, res) => {
const { name }: { name?: string } = req.params;
const plants = await db.getPlantsByCommonName(name);
res.send(plants);
});

Our routes use the PostgresService to make a call to getPlantsByCommonName and send the response back to the client. Now when you make a request such as http://localhost:3000/plants/{name}, it will return a response matching the common name you inserted.

Creating an Express Server

Now for the REST API. You need an entry point, so let’s create an index.ts file that contains a simple server.

import express from 'express';
const app = express();
const port = process.env.PORT || 3000;

app.listen(port, () =>
console.log(`🚀 Server ready at: http://localhost:3000`)
);

This is the simplest server we can set up. We listen for client requests at localhost 3000. Let’s go ahead and make requests to our server now.

As long as we mapped our common_name column correctly when we imported our CSV to our table, we should be able to make the following query:

http://localhost:3000/plants/acacia
Here is our data! It should return a list of plants with the common name of Acacia.

Let’s say that, instead of getting a plant by common name, we want to get all the plants that are native to a specific state.

Let’s add the following method to our PostgresService:

async getNativePlantsByState(state: string): Promise {
return await prisma.plants
.findMany({
where: {
state: {
contains: state,
},
native_status: {
contains: `${state} (N)`,
},
},
})
.then((res) => this.stringifyData(res));
}

If we want to do an x AND y search that meets a condition, we simply list them consecutively in our where object.

Now let us add our route for client requests.

router.get(‘/plants/state/:state’, async (req, res) => {
const { state }: { state?: string } = req.params;
const plants = await db.getNativePlantsByState(state);
res.send(plants);
});

We simply ask the client to make the request with the state they’re interested in and then only return plants with native status from that state.

So, we’ve got our REST API client successfully requesting and retrieving data regarding plants. Now what? Well, we want to host this express server somewhere so anyone can make requests to our API. Shall we make it a public-facing API? How do we do that and what security considerations should we be careful about?

We’ll answer all these questions in the next part of our series on creating an express server.