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.