My journey into GraphQL (part 2) - Getting started with Prisma

Anna Collins - Mar 5 '20 - - Dev Community

After learning the basics of GraphQL (see part 1 of my journey here), I got stuck in and started building stuff. Firstly, a small server using GraphQL Yoga, which made it super easy to get started! It’s built by the folks at Prisma who I’d heard great things about, so I wanted to find out what all the hype was about.

Prisma is an ORM. An ORM is a library which enables us to interact with a database from the server in a language of our choice. For example instead of having to write SQL to read and write to our My SQL database, we could use an ORM which would enable us to read and write to our database in JavaScript.

Prisma has all the abilities of other ORMs but it comes with some added extras. First of all it’s database agnostic. It currently supports Postgres, MySQL, MongoDB and Amazon RDS and they are working on support for a number of others including Elasticsearch, Cassandra and DynamoDB. You can read and write to your database in JavaScript, Typescript, Flow or Go. And the best part, it exposes your database as a GraphQL API, providing you with all basic CRUD operations and also GraphQL subscriptions. This means if we’re using GraphQL both between the client and the server, and between the server and the database, it makes the server really simple to write.

So let’s get started! Firstly you’ll need to install the Prisma CLI, which you can do from the command line with NPM $ npm install -g prisma. To run locally you will also need to have Docker installed on your machine. If you don’t have it, download the version for your operating system here.

Now we’ll need to create a database. You can connect a database you already have or create a new one. I’m going to set up a new one using Heroku since it’s really easy to use and for what we need right now it’s free. If you haven’t got an account already, sign up and then click on New in the top right and select create new app giving your app a name. When you are redirected to your app’s dashboard, click on Overview in the navbar and then for Installed add-ons click on Configure Add-ons and search for Heroku Postgres. For what we need we can select the free plan and once created, click to open Heroku Postgres and a new tab will open with your database dashboard. You can navigate to settings and view credentials for your database, we will be needing these in a moment to connect to Prisma.

We’re going to connect Prisma to a GraphQL Yoga server, so we will need to set up a server first. GraphQL Yoga is a server library and makes it easy to create a Node.js GraphQL server. It also provides GraphQL Playground, a GraphQL IDE that lets you interactively work with your GraphQL API. Create an empty project and run $ npm init. Create an index.js file where we’ll set up the server and install GraphQL Yoga $ npm install graphql-yoga.

To set up the server all we need to do is import GraphQLServer from graphql-yoga, create an instance of it, passing it the typeDefs and resolvers, and start the server. For now we can use a basic Hello World example.

const { GraphQLServer } = require('graphql-yoga')

const typeDefs = `
  type Query {
    hello(name: String): String!
  }
`

const resolvers = {
  Query: {
    hello: (_, { name }) => `Hello ${name || 'World'}`
  }
}

const server = new GraphQLServer({ typeDefs, resolvers })

server.start(() => console.log('Server is running on localhost:4000 🚀'))

Add a start script to your package.json file.

"scripts": {
   "start": "node index.js"
 },

And we’re good to go! Run $ npm run start and go to localhost:4000 to see the playground, the GraphQL IDE which allows you to interact with your server. You can explore the docs and schema using the tabs on the right, but for now we only have one query, hello.

Now to install Prisma in our project. Prisma is going to sit between our server and our datbase and we will be able to use the CRUD operations and subscriptions it provides to interact with our data, in our resolvers. Since we’ve already installed the CLI, we can run $ prisma init prisma, where prisma is the name we are going to give the prisma server in our project. Prisma will then guide you through a series of questions. We can select to use an existing database, select Postgres and then follow the steps to add your database credentials from Heroku. When asked to User SSL select yes and for the programming language for Prisma Client select Don’t generate as we are going to build the server ourselves. Here you could select a language and instead of writing your own schema and resolvers using Prisma to help, you could use what Prisma generates directly. Once finished, you should see the following new folder in your project.

  • prisma
    • datamodel.prisma
    • docker-compose.yml
    • prisma.yml

We have three new files, a yml file with some default config, a docker-compose.yml file which will start up our docker container and contains the connection to our database and finally, the file we are going to be changing will be the datamodel.prisma file. Here we define our types for which Prisma will generate the GraphQL API to interact with our database and which also defines the shape of our database. Let’s imagine we are creating a server for a blog. Our schema could consist of 3 types, for example:

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
  posts: [Post!]! @relation(onDelete: CASCADE)
  comments: [Comment!]! @relation(onDelete: CASCADE)
  updatedAt: DateTime! @updatedAt
  createdAt: DateTime! @createdAt
}

type Post {
  id: ID! @id
  title: String!
  body: String!
  published: Boolean!
  author: User! @relation(onDelete: SET_NULL)
  comments: [Comment!]! @relation(onDelete: CASCADE)
  updatedAt: DateTime! @updatedAt
  createdAt: DateTime! @createdAt
}

type Comment {
  id: ID! @id
  text: String!
  author: User! @relation(onDelete: SET_NULL)
  post: Post! @relation(onDelete: SET_NULL)
  updatedAt: DateTime! @updatedAt
  createdAt: DateTime! @createdAt
}

Fields can be decorated with @id, @createdAt and @updatedAt which are managed and created by Prisma and are read-only. Prisma ensures anything decorated with @unique will be unique. Prisma also has a type DateTime for time values in ISO format.

You will notice that some fields are decorated with @relation and are passed a value for onDelete. This is to tell prisma how to deal with related data when deleting an item. There are two values, SET_NULL and CASCADE. SET_NULL means that Prisma should simply delete the item itself and CASCADE means that Prisma should also delete any related items. For example you will notice on type User, on fields comments and posts, onDelete is set to CASCADE because if a user is deleted, all their posts and comments should also be deleted. Whereas on type Comment, onDelete on the author and post fields is set to SET_NULL because if a user’s comment is deleted, it’s not necessary to also delete the post or the user.

Now we’ve got our types defined in our datamodel.prisma file, it’s time to deploy our Prisma server. First we need to start the docker container. Make sure Docker is open and running on your machine and then start your container by running $ docker-compose up -D from inside the newly created prisma folder. We can then generate and deploy our Prisma server. Stay inside the prisma folder and run $ prisma deploy. Once finished, your Prisma server is deployed to localhost:4466 where you can see all the operations created in the schema tab. You can use this url to interact with your database and explore the operations Prisma has created for us. After deploying you can also see the changes reflected in your database. A User, Post and Comment table have been created with the columns corresponding to the fields on our types. You can use a GUI such as PGAdmin to connect to your database and see these changes.

The next step is to connect Prisma to our GraphQL Yoga server. To do this we need to create an instance of Prisma and pass it the required config. Install prisma-binding, $ npm install prisma-binding and create a new file prisma.js at the root of the project. One of the properties we need to pass our Prisma instance is the schema for the API it has generated. We can see all the operations in the playground at localhost:4466 but in the datamodel.prisma file in our project, we only have the types defined. We need to generate the full schema including all these operations we see in the playground to pass to our Prisma instance.

To do this we need graphql-cli so download it in your project, npm i graphql-cli, then create a .graphqlconfig file to tell graphql-cli how to generate our schema and where to save it.

{
  "projects": {
    "prisma-blog": {
      "schemaPath": "generated/prisma.graphql",
      "extensions": {
        "endpoints": {
          "default": "http://localhost:4466"
        }
      }
    }
  }
}

Here we tell graphql-cli to use our project with the name we gave it when initiating, prisma, at the endpoint localhost:4466 and to save the generated schema in a folder calledgenerated at the root of our project. Create a script to generate the schema in the package.json file.

"scripts": {
   "start": "node index.js",
   "get-schema": "graphql get-schema -p prisma"
 },

Run $ npm run get-schema and you will see the new folder with the generated schema at the root of your project. If you take a look at this file you can see that it is much bigger than the file where we defined the types and it now contains all the operations we can see in the playground. We can now create the instance of Prisma and pass it the schema we just generated and the endpoint.

const { Prisma } = require('prisma-binding')

const prisma = new Prisma({
  typeDefs: 'generated/prisma.graphql',
  endpoint: 'localhost:4466'
})

module.exports = prisma

And in our index.js file we import and add our instance of Prisma to the context in the server as follows

const { GraphQLServer } = require('graphql-yoga')
const prisma = require(“./prisma”)

const typeDefs = `
  type Query {
    hello(name: String): String!
  }
`

const resolvers = {
  Query: {
    hello: (_, { name }) => `Hello ${name || 'World'}`
  }
}

const server = new GraphQLServer({
  typeDefs,
  resolvers,
  context() {
    return {
      prisma,
    }
  }
})

server.start(() => console.log('Server is running on localhost:4000 🚀'))

So that’s us all set up and ready to start using Prisma in our own resolvers. In our server we should continue writing typeDefs and resolvers as normal, except in our resolvers we can now utilize Prisma to make interacting with our database super easy. I’m not going to go over how to write typeDefs or resolvers in this post but I will show you some examples of how you can use Prisma. You can explore the playground to see which arguments your new operations are expecting.

We can now read prisma from the context, the third argument passed to the resolvers. A really simple example would be a query to fetch all users. We need to pass the info argument as this will tell Prisma what data we want back for the user.

users(_, __, { prisma }, info) {
  return prisma.query.users(info)
},

Another example is a createPost mutation resolver. We pass the arguments in first and then the info as in the previous example.

createPost(_, args, { prisma }, info) {
  return prisma.mutation.createPost({
    data: {
      title: args.data.title,
      body: args.data.body,
      published: args.data.published,
      author: args.data.authorId
    }
  }, info)
}

And a final example we could have a deleteUser query. Remember, since we added @relation to the fields comment and post on this type with a onDelete value of CASCADE, this operation would also delete any comments or posts of the user.

deleteUser(_, args, { prisma }, info) {
  return prisma.mutation.deleteUser({
    where: {
      id: args.id
    }
  }, info)
},

The Prisma docs are pretty good and here you can find the documentation on how to use Prisma to interact with your database. Prisma also has an integration with Heroku to make deploying your server really easy too.

So there you go. You’re all set up to start writing your server using Prisma and since your database interactions are now so easy, you can concentrate more on other things like authentication in your sever. Prisma would be a great option for setting up a server quickly or for MVPs and here at Codegram we plan to start experimenting more with it. From a first glance I think it seems really cool and I’m looking forward to using it in production 🙌

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .