Node.js and GraphQL: Building APIs with Prisma

In recent years, GraphQL has gained popularity as a more efficient and flexible alternative to RESTful APIs. With its ability to selectively retrieve and manipulate data, GraphQL provides a powerful tool for building APIs that can adapt to changing client needs. In this article, we will explore how to build a GraphQL API using Node.js and Prisma, a modern database toolkit.

Prerequisites

To follow along with this tutorial, you should have some familiarity with Node.js, GraphQL, and database concepts. You will also need to have Node.js and npm (Node Package Manager) installed on your system.

Getting started

We will start by creating a new Node.js project and installing the necessary dependencies. Open your terminal and run the following commands:

bash
mkdir node-graphql-prisma
cd node-graphql-prisma
npm init -y
npm install --save graphql apollo-server prisma

The graphql package provides the tools we need to define our schema, the apollo-server package allows us to serve our GraphQL API over HTTP, and prisma is a powerful ORM (Object-Relational Mapping) tool that we will use to interact with our database.

Next, we will create a schema.graphql file in the root of our project and define our GraphQL schema. In this example, we will build a simple blogging platform with two types: User and Post.

graphql
type Query {
  users: [User!]!
  user(id: Int!): User
}

type User {
  id: Int!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: Int!
  title: String!
  body: String!
  author: User!
}

Our schema defines two query types (users and user) and two object types (User and Post). The users query returns an array of all users, the user query takes an id argument and returns a single user with that ID. The User object type has an id, name, email, and an array of Post objects. The Post object type has an id, title, body, and a reference to the User who authored it.

Next, we will define our Prisma schema. Prisma uses a separate schema to describe our database tables and their relationships. Create a schema.prisma file in the root of your project and define your schema as follows:

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

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

model User {
  id    Int     @id @default(autoincrement())
  name  String
  email String  @unique
  posts Post[]
}

model Post {
  id      Int     @id @default(autoincrement())
  title   String
  body    String
  author  User    @relation(fields: [authorId], references: [id])
  authorId Int
}

Our Prisma schema defines two models (User and Post) and a generator (client) that will generate the Prisma client, which we will use to interact with our database.

Our User model has an id, name, email, and an array of Post objects. The email field is marked as @unique, which ensures that each email is unique across all users. The Post model has an id, title, body, and a reference to the User who authored it.

Building the API

Now that we have defined our schema and Prisma schema, we can build our API. Create a new index.js file in the root of your project and add the following code:

javascript
const { ApolloServer } = require('apollo-server');
const { PrismaClient } = require('@prisma/client');

const prisma = new PrismaClient();

const typeDefs = `
  type Query {
    users: [User!]!
    user(id: Int!): User
  }

  type User {
    id: Int!
    name: String!
    email: String!
    posts: [Post!]!
  }

  type Post {
    id: Int!
    title: String!
    body: String!
    author: User!
  }
`;

const resolvers = {
  Query: {
    users: async () => {
      return await prisma.user.findMany();
    },
    user: async (_, { id }) => {
      return await prisma.user.findUnique({
        where: { id: id }
      });
    }
  },
  User: {
    posts: async (parent) => {
      return await prisma.post.findMany({
        where: { authorId: parent.id }
      });
    }
  },
  Post: {
    author: async (parent) => {
      return await prisma.user.findUnique({
        where: { id: parent.authorId }
      });
    }
  }
};

const server = new ApolloServer({ typeDefs, resolvers });

server.listen().then(({ url }) => {
  console.log(`Server running at ${url}`);
});

This code sets up our GraphQL server using the ApolloServer class from the apollo-server package. We create a new instance of the PrismaClient class from the @prisma/client package, which provides us with an ORM for our database. We define our typeDefs and resolvers, which define our GraphQL schema and the functions that resolve the queries and mutations.

Our users query simply returns all users from the database using the findMany() method on the prisma.user object. Our user query takes an id argument and returns a single user with that ID using the findUnique() method.

The posts field on the User object type uses the findMany() method on the prisma.post object to return all posts authored by that user. The author field on the Post object type uses the findUnique() method on the prisma.user object to return the user who authored that post.

Finally, we create a new instance of the ApolloServer class, passing in our typeDefs and resolvers. We start the server listening on a port and log a message to the console indicating that the server is running.

Testing the API

Now that we have built our API, we can test it using a GraphQL client like GraphiQL or Apollo Studio. To test our API, we will start the server by running node index.js in the terminal. Once the server is running, we can open GraphiQL in our browser at http://localhost:4000/graphql (or the URL indicated in the console message).

In the GraphiQL interface, we can run queries against our API. For example, we can retrieve all users using the following query:

graphql
query {
  users {
    id
    name
    email
    posts {
      id
      title
      body
    }
  }
}

Conclusion

In this article, we have explored how to use Prisma and GraphQL to build a flexible and efficient API in Node.js. We first defined our schema using the GraphQL schema language, then used Prisma to generate a database schema and connect to our database. Finally, we built our API using the Apollo Server library, defining our resolvers to handle incoming queries and mutations.

By using Prisma and GraphQL together, we have created an API that is easy to maintain and modify as our application grows and evolves. With Prisma, we have a powerful ORM that allows us to abstract away the details of our database, while still being able to take full advantage of its capabilities. With GraphQL, we have a flexible query language that allows our clients to request only the data they need, and nothing more.

0368826868