Photo credit: https://www.prisma.io/blog/prisma-client-preview-ahph4o1umail/

ORMs (Object Relational Mappings) get a ton of hate amongst engineers today. We often look at ORMs with disdain writing them off as “leaky abstractions” over our database. But time and time again, engineering teams still use ORMs! Often they start with an ORM and use them with full force until they start hitting performance issues. Once the bottlenecks hit, many teams fork their current library and add more abstractions on top of it to fit their business need! I think this is because most ORMs abstract naive database operations very well, but leave users to step down into native APIs to handle more complex scenarios.

Picture credit to @hidace in this post

Martin Fowler addressed this “hate” on ORMs in his post here. I do think the solution he proposes makes sense: own the relational model all the way through your application.

With Prisma, we do just that.

We describe our database models with the GraphQL SDL (Schema Definition Language) and then map this data model to a GraphQL API compliant with the Open CRUD specification. These APIs represent the “data access layer” sitting above your database (SQL, Postgres, Mongo) with the responsibility of making efficient queries against your database. Effectively we have created a “GraphQL ORM” for your database.

Let’s see how this plays out.

We define a type User using the SDL syntax.

Prisma will then generate the GraphQL API below. I’ve omitted the input types just to show off the core APIs exposed.

As you can see for our type User, we have generated a GraphQL Schema describing Query, Mutation, and Subscription operations. Now we can send GraphQL queries to the data access layer to interact with our database!

Now that we have a general idea of how Prisma abstracts our database, let’s revisit ORMs with a new example.

Prisma Client

Prisma Client represents an ambition. How can we access our database with an ORM-like experience without an actual ORM.

Enter Prisma Client.

We’re going to build out a simple REST API with Prisma to show off the experience of using Prisma Client. The architecture should follow the diagram below.

Photo credit: prisma.io

Project Setup

First let’s bootstrap a new project.

$ mkdir prisma-rest-example
$ cd prisma-rest-example

Next let’s install the Prisma CLI globally on your machine via NPM.

$ npm install -g prisma@1.20.1

Let’s put our Prisma artifacts in a prisma folder.

$ mkdir prisma

We need three things to get a Prisma API started

  1. datamodel.prisma — Your database model expressed in SDL syntax
  2. prisma.yml — Configuration of your Prisma server
  3. docker-compose.yml — Docker compose file describing the Prisma server image and your database image.

Datamodel

$ cd prisma
$ touch datamodel.prisma

Paste the following datamodel into your datamodel.prisma file.

We’re going to use a simple example. A User with posts and a Post with an author.

prisma.yml

$ touch prisma.yml

Paste the following configuration into the prisma.yml file.

Let’s break down what is in this file.

  • endpoint — the remote url for the Prisma server
  • datamodel — the datamodel.prisma file
  • generate — The generator for our Prisma Client

The generate field is the interesting one here. When the Prisma CLI runs generate, it will output a Prisma Client API based on a generator. In our example here we are using the typescript-client, but you could use a variety of clients like golang, flow, and javascript.

More client generators will be added as engineers from different language communities adopt Prisma Client!

docker-compose.yml

$ cd ..
$ touch docker-compose.yml

Paste the following content into your docker-compose.yml file. This file is located in the root of your project.

Here we setup two services: the Prisma base image and MySQL.

Running the server

Now that we have our configuration files in place, let’s deploy a Prisma server.

First in the root of your project, start your containers with docker-compose.

$ docker-compose up -d

This will pull the public images for prisma and mysql and run them on our machine via docker.

Next we need to deploy our datamodel to our server. Execute the commands below.

$ prisma deploy

You can see that the Prisma server has taken our datamodel and generated the GraphQL API.

Let’s open up the GraphQL Playground to interact with our database.

Here we create a new User in our database using the createUser API generated from our datamodel. We can query this User now!

Generating the client

Okay so now that we have a data access layer on top of our database, the next thing we need to do is generate a client we can use in the application tier.

To generate a Prisma Client execute the command below.

$ prisma generate

This will generate a prisma-client folder in your src/generated folder.

Let’s setup our REST API and we will revisit the client shortly.

First thing let’s bootstrap our package.json with yarn.

$ yarn init -y

Next in the root of our project let’s install some dev-dependencies.

$ yarn add typescript ts-node -D

Let’s setup a tsconfig.json in the root of our project.

$ touch tsconfig.json

Copy the following content into your tsconfig.json file.

To use our client we need to install graphql and the prisma-client-lib.

$ yarn add prisma-client-lib@1.20.1 graphql -S
$ yarn add @types/graphql -D

Now we need to install a web server, we’ll use Express.js.

$ yarn add express body-parser -S$ yarn add @types/express @types/body-parser -D

Next create an entry point to the server.

$ cd src
$ touch index.ts

Let’s add a start script to our package.json.

"scripts": {
"start": "ts-node ./src/index.ts"
}

Time to scaffold our endpoints. Copy the following content into your index.ts

Implementing APIs

Creating a User

First we need to import the client from ./src/generated/prisma-client and then we can implement the create/user endpoint.

This is shown below.

Here we get the input arguments from the request body, use the Prisma Client much like an ORM and use the createUser method. We’ll respond 200 and return the newly created User.

Fetching a User

Next we can implement a query to find a User by a specific ID.

Just like creating a User, the client has a simple approach to fetching a User.

Let’s see if everything works. Open up your terminal in the root of this project and type:

$ yarn start

Now we can open up POSTMAN or a similar tool to make a request.

Sweet that worked! Let’s fetch the newly created User.

Awesome! You can see how this is a nice developer experience for interacting with your database.

Creating a Post

Now we’ll implement creating a post.

This is where things get a bit more interesting! If we remember the Post type in our datamodel has an author field. This is a relation to the User. So when we create our Post we use the connect syntax to “connect” this Post to a User.

Publishing a Post

So we just implemented creating “draft” posts. Let’s implement the endpoint that makes the published field on a Post true.

Here we use the updatePost method which has 2 requirements. First a selector for the item using the where syntax. Last, a data object describing the change. We find a Post where the id matches the id of our request and change the published field to true. Sweet.

Fetching a Post

This looks identical to fetching a user.

And we can test it.

But wait! Our Post type specifies an author field as well. By default queries against a type does not resolve relations. To fetch the author as well, let’s modify our code.

We can access the relation by calling the author method once we have a post!

Fetching Posts/Draft Posts

I hope as we are going down the list of endpoints, implementing each one is getting easier for you to understand how easy to use Prisma Client is! Let’s finish up these APIs.

Here we just use the posts method on the client to fetch posts whether published is true or not. We could further get the authors for each post by mapping the posts array to fetch each author field but we have omitted that here to keep this example simple.

Fetching published posts
Fetching draft posts

Conclusion

Using the Prisma Client has been a really great experience for building CLIs, GraphQL Servers, REST APIs, Webhooks, you name it. I love that it abstracts the annoyances of data access and gives you a nice API client with a pretty expressive syntax! We used typescript in this example, but you can generate the client in your favorite languages and start integrating it into your stack.

The source code for this blog post is located below.

Software Engineer at Workpop, Inc.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store