DEV Community

Nditah
Nditah

Posted on • Edited on

How To Build a GraphQL API with Node.js, Prisma, Docker and Postgres

Introduction

REST (REpresentational State Transfer) is an architectural style for distributed hypermedia systems.
An API is a set of definitions and protocols for building and integrating application software.
Whereas REST is an architectural style, GraphQL is data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.
GraphQL was developed to solves many of the challeneges of flexibility and efficiency that developers encountered when interacting with RESTful APIs.
GraphQL is not a programming language capable of arbitrary computation, but is instead a language used to make requests to application services that have capabilities defined in this specification.

Prisma is an open-source ORM for Nodejs and TypeScript. In our previous lesson on "How To Build a REST API with Node.js, Prisma ORM, PostgreSQL Database, and Docker" you implemented your first REST API Route. Today, we are going to take a step further to build a Grapghql API with Nodejs, Prisma, and Postgres.

In this lesson, you will use GraphQL and Prisma in combination as their responsibilities complement each other.
Youโ€™ll build a GraphQL API for a college management application in JavaScript using Node.js.
You will first use ApolloServer to build the GraphQL API backed by in-memory data structures.

Content

๐Ÿ”ท Step 1 โ€” Creating the Node.js Project

๐Ÿ”ท Step 2 โ€” Defining the GraphQL Schema

๐Ÿ”ท Step 2 โ€” Defining the GraphQL Resolvers

๐Ÿ”ท Step 3 โ€” Creating the GraphQL Server

๐Ÿ”ท Step 4 โ€” Setting Up Prisma with PostgreSQL

๐Ÿ”ท Step 5 โ€” Defining the Data Model with Prisma Migrate

๐Ÿ”ท Step 6 โ€” Using Prisma Client in the GraphQL Resolvers

๐Ÿ”ท Step 7 โ€” Creating and Migrating the PostgreSQL Database in App Platform

๐Ÿ”ท Step 8 โ€” Modifying the Student Model

๐Ÿ”ท Step 9 โ€” Testing

The Github repository of this project can be found here.

Prerequisites

  • Node.js v10 to v14
  • Docker installed on your computer (to run the PostgreSQL database locally).
  • Basic familiarity with Node.js is helpful, but not strictly required for this lesson.

Step 1 โ€” Creating the Node.js Project

In this step, you will set up a Node.js project with npm and install the dependencies apollo-server and graphql.

This project will be the foundation for the GraphQL API that youโ€™ll build and deploy throughout this tutorial.

First, create a new directory for your project:

$ mkdir node-graphql
Enter fullscreen mode Exit fullscreen mode

Next, navigate into the directory and initialize an empty npm project:

cd node-graphql
npm init --yes
Enter fullscreen mode Exit fullscreen mode

This command creates a minimal package.json file that is used as the configuration file for your npm project.

You will receive the following output:

Output
Wrote to /home/Projects/lesson/node-graphql/package.json:
{
  "name": "node-graphql",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
Enter fullscreen mode Exit fullscreen mode

Youโ€™re now ready to configure TypeScript in your project.

Execute the following command to install the necessary dependencies:

$ npm install apollo-server graphql
Enter fullscreen mode Exit fullscreen mode

This installs two packages as dependencies in your project:

  • apollo-server: The HTTP library that you use to define how GraphQL requests are resolved and how to fetch data.

  • graphql: is the library youโ€™ll use to build the GraphQL schema.

Youโ€™ve created your project and installed the dependencies. In the next step you will define the GraphQL schema.

Step 2 โ€” Defining the GraphQL Schema and Resolvers

In this step, you will define the GraphQL schema and corresponding resolvers. The schema will define the operations that the API can handle. The resolvers will define the logic for handling those requests using in-memory data structures, which you will replace with database queries in the next step.

First, create a new directory called src that will contain your source files:

$ mkdir src
Enter fullscreen mode Exit fullscreen mode

Then run the following command to create the file for the schema:

$ touch src/schema.js
Enter fullscreen mode Exit fullscreen mode

Now add the following code to the file:

//* node-graphql/src/schema.js

const { gql } = require('apollo-server')

const typeDefs = gql`

  type Student {
    id: ID!
    email: String!
    fullName: String!
    dept: String
    enrolled: Boolean
  }

  type Query {
    enrollment: [Student!]
    students: [Student!]!
    student(id: ID!): Student
  }

  type Mutation {
    registerStudent(email: String!, fullName: String!, dept: String): Student!
    enroll(id: ID!): Student
  }
`
module.exports = {
  typeDefs,
}
Enter fullscreen mode Exit fullscreen mode

Here you define the GraphQL schema using the gql tagged template. A schema is a collection of type definitions (hence typeDefs) that together define the shape of queries that can be executed against your API. This will convert the GraphQL schema string into the format that Apollo expects. Node the ! sign on id: ID! for example. It means id of type ID cannot be null. Read more from here.

The schema introduces three types:

  • Student: Defines the type for a student in your college app and contains four fields where each field is followed by its type, for example, String.

  • Query: Defines the enrollment query which returns multiple students as denoted by the square brackets and the student query which accepts a single argument and returns a single Student.

  • Mutation: Defines the registerStudent mutation for creating a registering Student and the enroll mutation which accepts an id and returns a Student.

Note that every GraphQL API has a query type and may or may not have a mutation type. These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.

Next, create a file database.js in your project src and add the students array to it as shown below:


// node-graphql/src/database.js

const students = [
    {
      id: 1,
      email: 'ada@telixia.com',
      fullName: 'Ada Eze',
      dept: 'Software Engineering',
      enrolled: true,
    },
    {
      id: 2,
      email: 'musa@telixia.com',
      fullName: 'Musa Bashir',
      dept: 'Data Engineering',
      enrolled: true,
    },
    {
      id: 3,
      email: 'ola@telixia.com',
      fullName: 'Omolara Liza',
      dept: 'System Security',
      enrolled: false,
    },
  ]

  module.exports = {
    students,
  }


Enter fullscreen mode Exit fullscreen mode

You define the students array with three pre-defined students. Notice that the structure of each student object matches the Student type you defined in the schema. This array holds the students that will be served by the API. In a subsequent step, you will replace the array once the database and Prisma Client are introduced.

Next, create a file resolver.js in your project src and define the resolvers object. Import the students array to it as shown below:

// node-graphql/src/resolvers.js

const { students } =  require('./database.js');

const resolvers = {

    Student: {
        id: (parent, args, context, info) => parent.id,
        email: (parent) => parent.email,
        fullName: (parent) => parent.fullName,
        dept: (parent) => parent.dept,
        enrolled: (parent) => parent.enrolled,
      },

    Query: {
      enrollment: (parent, args) => {
        return students.filter((student) => student.enrolled)
      },
      student: (parent, args) => {
        return students.find((student) => student.id === Number(args.id))
      },
    },

    Mutation: {
      registerStudent: (parent, args) => {
        students.push({
          id: students.length + 1,
          email: args.email,
          fullName: args.fullName,
          dept: args.dept,
          enrolled: false,
        })
        return students[students.length - 1]
      },
      enroll: (parent, args) => {
        const studentToEnroll = students.find((student) => student.id === Number(args.id))
        studentToEnroll.enrolled = true
        return studentToEnroll
      },
    },

  }


  module.exports = {
    resolvers,
  }

Enter fullscreen mode Exit fullscreen mode

You define the resolvers following the same structure as the GraphQL schema. Every field in the schemaโ€™s types has a corresponding resolver function whose responsibility is to return the data for that field in your schema. For example, the Query.enrollment() resolver will return the enrolled students by filtering the students array.

Resolver functions receive four arguments namely: parent, args, context, and info. See a brief explanation below:

  1. parent: The parent is the return value of the previous resolver in the resolver chain. For top-level resolvers, the parent is undefined, because no previous resolver is called. For example, when making a enrollment query, the query.enrollment() resolver will be called with parentโ€™s value undefined and then the resolvers of Student will be called where parent is the object returned from the enrollment resolver.

  2. args: This argument carries the parameters for the query, for example, the student query, will receive the id of the student to be fetched.

  3. context: An object that gets passed through the resolver chain that each resolver can write to and read from, which allows the resolvers to share information.

  4. info: An AST representation of the query or mutation. You can read more about the details in part III of this series: Demystifying the info Argument in GraphQL Resolvers.

Since the context and info are not necessary in these resolvers, only parent and args are defined.

Step 3 โ€” Creating the GraphQL Server

In this step, you will create the GraphQL server with Apollo Server and bind it to a port so that the server can accept connections.

First, run the following command to create the file for the server:

$ touch src/index.js
Enter fullscreen mode Exit fullscreen mode

Now add the following code to the file:

// node-graphql/src/index.js

const { ApolloServer } = require('apollo-server')
const { typeDefs } = require('./schema')
const { resolvers } = require('./resolvers')

const port = process.env.PORT || 9090;

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

server.listen({ port }, () => console.log(`Server runs at: http://localhost:${port}`));

Enter fullscreen mode Exit fullscreen mode

Here you instantiate the server and pass the imported resolvers and typeDefs from the previous step.

The port the server will bind to is set from the PORT environment variable and if not set, it will default to 9090. The PORT environment variable will be automatically set by App Platform and ensure your server can accept connections once deployed.

Your GraphQL API is ready to run. Start the server with the following command:

$ node src/index.js
Enter fullscreen mode Exit fullscreen mode

You will receive the following output:

Output
Server ready at: http://localhost:9090
Enter fullscreen mode Exit fullscreen mode

Itโ€™s considered good practice to add a start script to your package.json so that the entry point to your server is clear. Moreover, this will allow App Platform to start the server once deployed.

To do so, add the following line to the "scripts" object in package.json:

{
  "name": "node-graphql",
  "version": "1.0.0",
  "description": "Grapghql API with Nodejs, Prisma, Postgres and Docker",
  "main": "index.js",
  "scripts": {
    "start":  "node src/"
  },
  "keywords": ["Grapghql", "API", "Node.js", "Prisma", "Postgres", "Docker"],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "apollo-server": "^2.18.2",
    "graphql": "^15.3.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now you can start the server with the following command:

$ npm start
Enter fullscreen mode Exit fullscreen mode

To test the GraphQL API, open the URL from the output, which will lead you to the GraphQL Playground.

If you encounter and error like this:

Error: listen EADDRINUSE: address already in use :::9090
    at Server.setupListenHandle [as _listen2] (net.js:1320:16)
    at listenInCluster (net.js:1368:12)
    at Server.listen (net.js:1454:7)
    at /home/peace/Projects/Lesson/node-graphql/node_modules/apollo-server/dist/index.js:74:24
    at new Promise (<anonymous>)
    at ApolloServer.listen (/home/peace/Projects/Lesson/node-graphql/node_modules/apollo-server/dist/index.js:72:15)
Emitted 'error' event on Server instance at:
    at emitErrorNT (net.js:1347:8)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  code: 'EADDRINUSE',
  errno: -98,
  syscall: 'listen',
  address: '::',
  port: 9090
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! node-graphql@1.0.0 start: `node ./src`
npm ERR! Exit status 1
Enter fullscreen mode Exit fullscreen mode
$ npx kill-port 9090
$ npm start
Enter fullscreen mode Exit fullscreen mode

GraphQL Playground - Default Screen

CLick on Query your server

GraphQL Playground

The GraphQL Playground is an IDE where you can test the API by sending queries and mutations.

For example, to test the enrollment query which only returns enrolled students, enter the following query to the left side of the IDE and send the query by pressing the Run button:

Operation

query ExampleQuery {
  enrollment {
    id
    email
    fullName
    dept
  }
}
Enter fullscreen mode Exit fullscreen mode

Response

{
  "data": {
    "enrollment": [
      {
        "id": "1",
        "email": "ada@telixia.com",
        "fullName": "Ada Eze",
        "dept": "Software Engineering"
      },
      {
        "id": "2",
        "email": "musa@telixia.com",
        "fullName": "Musa Bashir",
        "dept": "Data Engineering"
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

GraphQL Playground - Query and Result

To test the registerStudent mutation, enter the following mutation:

Operation

mutation {
  registerStudent(
    email: "contact@telixia.com",
    fullName: "Sammy",
    ) {
    id
    email
    fullName
    dept
    enrolled
  }
}
Enter fullscreen mode Exit fullscreen mode

Response

 {
  "data": {
    "registerStudent": {
      "id": "4",
      "email": "contact@telixia.com",
      "fullName": "Sammy",
      "dept": null,
      "enrolled": false
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Note: You can choose which fields to return from the mutation by adding or removing fields within the curly braces following registerStudent. For example, if you wanted to only return the id and email you could simple omit the fullName, dept and enrolled field.

You have successfully created and tested the GraphQL server. In the next step, you will create a GitHub repository for the project.

Step 4 โ€” Creating the GitHub Repository

In this step, you will create a GitHub repository for your project and push your changes so that the GraphQL API can be automatically deployed from GitHub to any cloud platform of your choice.

Begin by initializing a repository from the prisma-graphql folder:

$ git init
Enter fullscreen mode Exit fullscreen mode

To avoid committing the node_modules folder and the .env file, begin by creating a .gitignore file:

$ touch .gitignore
Enter fullscreen mode Exit fullscreen mode
# .gitignore 
# Specifies intentionally untracked files to ignore when using Git
# http://git-scm.com/docs/gitignore

.vscode/
npm-debug.log*
node_modules/

Enter fullscreen mode Exit fullscreen mode

Next, use the following two commands to commit the code to the repository:

$ git add .
$ git commit -m 'Initial commit'
Enter fullscreen mode Exit fullscreen mode

Now that the changes have been committed to your local repository, you will create a repository in GitHub and push your changes.

Go to GitHub to create a new repository. For consistency, name the repository node-graphql-lesson-03 and then click Create repository.

After the repository was created, push the changes with the following commands, which includes renaming the default local branch to main:

$ git remote add origin git@github.com:<USERNAME>/node-graphql-lesson-03.git
$ git branch -M main
$ git push --set-upstream origin main
Enter fullscreen mode Exit fullscreen mode

You have successfully committed and pushed the changes to GitHub.

Step 6 โ€” Setting Up Prisma with PostgreSQL

So far the GraphQL API you built used the in-memory students array in the database.js file to store data. This means that if your server restarts, all changes to the data will be lost. To ensure that your data is safely persisted, you will replace the database.js with a PostgreSQL database and use Prisma to access the data.

In this step, you will install the Prisma CLI, create your initial Prisma schema, set up PostgreSQL locally with Docker, and connect Prisma to it.

The Prisma schema is the main configuration file for your Prisma setup and contains your database schema.

Begin by installing the Prisma CLI with the following command:

$ npm install prisma -D
Enter fullscreen mode Exit fullscreen mode

The Prisma CLI will help with database workflows such as running database migrations and generating Prisma Client.

Next, youโ€™ll set up your PostgreSQL database using Docker. Create a new Docker Compose file with the following command:

$  touch docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

Now add the following code to the newly created file:


# node-graphql/docker-compose.yml

version: '3.8'
services:
  postgres:
    image: postgres:13
    restart: always
    environment:
      - POSTGRES_USER=db_user
      - POSTGRES_PASSWORD=db_password
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - '5432:5432'
volumes:
  postgres:
Enter fullscreen mode Exit fullscreen mode

This Docker Compose configuration file is responsible for starting the official PostgreSQL Docker image on your machine. The POSTGRES_USER and POSTGRES_PASSWORD environment variables set the credentials for the superuser (a user with admin privileges). You will also use these credentials to connect Prisma to the database. Finally, you define a volume where PostgreSQL will store its data, and bind the 5432 port on your machine to the same port in the Docker container.

With this setup in place, go ahead and launch the PostgreSQL database server with the following command:

$ docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

The Output:

Creating network "node-graphql_default" with the default driver
Creating volume "node-graphql_postgres" with default driver
Creating node-graphql_postgres_1 ... done
Enter fullscreen mode Exit fullscreen mode

You can verify that the database server is running with the following command:

$ docker ps
Enter fullscreen mode Exit fullscreen mode

This will output something similar to:

CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                                       NAMES
ca2813291692   postgres:13   "docker-entrypoint.sโ€ฆ"   40 seconds ago   Up 35 seconds   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   node-graphql_postgres_1
Enter fullscreen mode Exit fullscreen mode

With the PostgreSQL container running, you can now create your Prisma setup. Run the following command from the Prisma CLI:

$ npx prisma init
Enter fullscreen mode Exit fullscreen mode

Note that as a best practice, all invocations of the Prisma CLI should be prefixed with npx. This ensures itโ€™s using your local installation.

After running the command, the Prisma CLI created a new folder called prisma in your project. It contains the following two files:

  • schema.prisma: The main configuration file for your Prisma project (in which you will include your data model).
  • .env: A dotenv file to define your database connection URL.

To make sure Prisma knows about the location of your database, open the prisma/.env file:

Adjust the DATABASE_URL environment variable to look as follows:

# node-graphql/prisma/.env

DATABASE_URL="postgresql://db_user:db_password@localhost:5432/college_db?schema=public"
Enter fullscreen mode Exit fullscreen mode

Note that youโ€™re using the database credentials db_user and db_password, which are specified in the Docker Compose file. To learn more about the format of the connection URL, visit the Prisma docs.

You have successfully started PostgreSQL and configured Prisma using the Prisma schema. In the next step, you will define your data model for the Student and use Prisma Migrate to create the database schema.

Step 7 โ€” Defining the Data Model with Prisma Migrate

Now you will define your data model in the Prisma schema file youโ€™ve just created. This data model will then be mapped to the database with Prisma Migrate, which will generate and send the SQL statements for creating the tables that correspond to your data model.

Since youโ€™re building a college portal, the main entities of the application will be students, teachers and courses. In this step, you will define a Student model with a similar structure to the Student type in the GraphQL schema. In a later step, you will evolve the app and add a Teacher and Course models.

Note: The GraphQL API can be seen as an abstraction layer for your database. When building a GraphQL API, itโ€™s common for the GraphQL schema to closely resemble your database schema. However, as an abstraction, the two schemas wonโ€™t necessarily have the same structure, thereby allowing you to control which data you want to expose over the API. This is because some data might be considered sensitive or irrelevant for the API layer.

Prisma uses its own data modeling language to define the shape of your application data.

Go to node-graphql/prisma/schema.prisma Add the following model definitions to it:

//* node-graphql/prisma/schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

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

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

model Student {
  id       Int     @id @default(autoincrement())
  email    String
  fullName String
  dept     String?
  enrolled Boolean @default(false)
}

Enter fullscreen mode Exit fullscreen mode

You are defining a model called Student with a number of fields. The model will be mapped to a database table; the fields represent the individual columns.

The id fields have the following field attributes:

  • @default(autoincrement()) : This sets an auto-incrementing default value for the column.

  • @id: This sets the column as the primary key for the table.

With the model in place, you can now create the corresponding table in the database using Prisma Migrate. This can be done with the migrate dev command that creates the migration files and runs them.

Open up your terminal again and run the following command:

$ npx prisma migrate dev --name "init" 
Enter fullscreen mode Exit fullscreen mode

This will output something similar to:

Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "college_db", schema "public" at "localhost:5432"

PostgreSQL database college_db created at localhost:5432

The following migration(s) have been created and applied from new schema changes:

migrations/
  โ””โ”€ 20210815160400_init/
    โ””โ”€ migration.sql

Your database is now in sync with your schema.
Enter fullscreen mode Exit fullscreen mode

This command creates a new migration on your file system and runs it against the database to create the database schema. Hereโ€™s a quick overview of the options that are provided to the command:

  • --name "init": Specifies the name of the migration (will be used to name the migration folder thatโ€™s created on your file system).

  • --skip-generate: Skips generating Prisma Client (this will be done in the next step).

Your prisma/migrations directory is now populated with the SQL migration file. This approach allows you to track changes to the database schema and create the same database schema in production.

Note: If youโ€™ve already used Prisma Migrate with the college_db database and there is an inconsistency between the migrations in the prisma/migration folder and the database schema you will be prompted to reset the database with the following output:

Output
? We need to reset the PostgreSQL database "college_db" at "localhost:5432". All data will be lost.
Do you want to continue? โ€บ (y/N)
You can resolve this by entering y which will reset the database. Beware that this will cause all data in the database to be lost.
Enter fullscreen mode Exit fullscreen mode

Youโ€™ve now created your database schema. In the next step, you will install Prisma Client and use it in your GraphQL resolvers.

Step 8 โ€” Using Prisma Client in the GraphQL Resolvers

Prisma Client is an auto-generated and type-safe Object Relational Mapper (ORM) that you can use to programmatically read and write data in a database from a Node.js application. In this step, youโ€™ll install Prisma Client in your project.

Open up your terminal again and install the Prisma Client npm package:

$  npm install @prisma/client
Enter fullscreen mode Exit fullscreen mode

Note: Prisma Client gives you rich auto-completion by generating code based on your Prisma schema to the node_modules folder. To generate the code you use the npx prisma generate command. This is typically done after you create and run a new migration. On the first install, however, this is not necessary as it will automatically be generated for you in a postinstall hook.

With the database and GraphQL schema created, and Prisma Client installed, you will now use Prisma Client in the GraphQL resolvers to read and write data in the database. Youโ€™ll do this by replacing the content of the database.js, which youโ€™ve used so far to hold your data.

//* node-graphql/src/database.js

const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient();

module.exports = {
  prisma,
}


Enter fullscreen mode Exit fullscreen mode

Now you will update the Query resolvers to fetch enrolled students from the database. Update the resolvers.Query object with the following resolvers:

//* node-graphql/src/resolvers.js


const resolvers = {
  Query: {
    enrollment: (parent, args) => {
      return prisma.student.findMany({
        where: { enrolled: true },
      });
    },
    student: (parent, args) => {
      return prisma.student.findFirst({
        where: { id: Number(args.id) },
      });
    },
  },
Enter fullscreen mode Exit fullscreen mode

Here, youโ€™re using two Prisma Client queries:

  • findMany: Fetches students whose enrolled field is false.

  • findOne: Fetches a single student whose id field equals the id GraphQL argument.

Note, that as per the GraphQL specification, the ID type is serialized the same way as a String. Therefore you convert to a Number because the id in the Prisma schema is an int.

Next, you will update the Mutation resolver to save and update students in the database. Update the resolvers.Mutation Object with the following resolvers:


//* node-graphql/src/resolvers.js



const resolvers = {
  ...
  Mutation: {
    registerStudent: (parent, args) => {
      return prisma.student.create({
        data: {
          email: args.email,
          fullName: args.fullName,
        },
      });

    },
    enroll: (parent, args) => {
      return prisma.student.update({
        where: {
          id: Number(args.id),
        },
        data: {
          enrolled: true,
        },
      });
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

Final resolvers.js looks like this:

//* node-graphql/src/resolvers.js

const { prisma } = require("./database.js");

const Student = {
  id: (parent, args, context, info) => parent.id,
  email: (parent) => parent.email,
  fullName: (parent) => parent.fullName,
  dept: (parent) => parent.dept,
  enrolled: (parent) => parent.enrolled,
};

const Query = {
  enrollment: (parent, args) => {
    return prisma.student.findMany({
      where: { enrolled: true },
    });
  },
  students: (parent, args) => {
    return prisma.student.findMany({});
  },
  student: (parent, args) => {
    return prisma.student.findFirst({
      where: { id: Number(args.id) },
    });
  },
};

const Mutation = {
  registerStudent: (parent, args) => {
    return prisma.student.create({
      data: {
        email: args.email,
        fullName: args.fullName,
        dept: args.dept,
      },
    });
  },
  enroll: (parent, args) => {
    return prisma.student.update({
      where: { id: Number(args.id) },
      data: {
        enrolled: true,
      },
    });
  },
};

const resolvers = { Student, Query, Mutation };

module.exports = {
  resolvers,
};
Enter fullscreen mode Exit fullscreen mode

Youโ€™re using two Prisma Client queries:

  • create: Create a Student record.

  • update: Update the enrolled field of the Student record whose id matches the one in the query argument.

Now that youโ€™ve updated the resolvers to use Prisma Client, start the server to test the flow of data between the GraphQL API and the database with the following command:

$ npm start 
Enter fullscreen mode Exit fullscreen mode

Open the GraphQL playground at the address from the output and test the GraphQL API using the same queries from Step 3.

Then run the following two commands to commit the changes:

$  git add .
$  git commit -m 'Feature: Add Prisma'
$  git push
Enter fullscreen mode Exit fullscreen mode

Run the migrations against the database with Prisma Migrate.

$ npx prisma migrate dev
Enter fullscreen mode Exit fullscreen mode

Testing

Create Student

mutation {
  registerStudent(email: "Olivia@telixia.com", fullName: "Olivia Catherine", dept: "Backend Engineer") {
    id
    fullName
    dept
    email
    enrolled

  }
}
Enter fullscreen mode Exit fullscreen mode

Result

{
  "data": {
    "registerStudent": {
      "id": "2",
      "fullName": "Olivia Catherine",
      "dept": "Backend Engineer",
      "email": "Olivia@telixia.com",
      "enrolled": false
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Enroll Student

mutation {
  enroll(id: 2) {
    id
    fullName
    email
    dept
    enrolled
  }
}
Enter fullscreen mode Exit fullscreen mode

Result

{
  "data": {
    "enroll": {
      "id": "2",
      "fullName": "Olivia Catherine",
      "email": "Olivia@telixia.com",
      "dept": "Backend Engineer",
      "enrolled": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Query

query Query {
  enrollment {
    id
    email
    fullName
    dept
    enrolled
  }
}
Enter fullscreen mode Exit fullscreen mode

Result

{
  "data": {
    "enrollment": [
      {
        "id": "1",
        "email": "felix@telixia.com",
        "fullName": "Musah Felix",
        "dept": null,
        "enrolled": true
      },
      {
        "id": "2",
        "email": "Olivia@telixia.com",
        "fullName": "Olivia Catherine",
        "dept": "Backend Engineer",
        "enrolled": true
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Congratulations! You have completed the first part of Node Backend with Graphql and Prisma.
You will discover the full advantage in a more advance backend application with more than two models having a relationship.
A good example is having not only student, but also Teacher, Department, Courses Models added to our application.

Further Reading

[1] Lext Lesson to learn more on how to How To Build a GraphQL API with Apollo-Server and Prisma

[2] Prisma Fluent-Api

[3] Prisma Components

[4] Introduction to GraphQl

[5] Introduction to Apollo Server

Happy Reading & Coding

๐Ÿ’ป ๐Ÿ““ ๐Ÿ’ ๐Ÿ“• ๐Ÿ’“ ๐Ÿ“— ๐Ÿ’– ๐Ÿ“˜ ๐Ÿ’— ๐Ÿ“™ ๐Ÿ’œ ๐Ÿ“” ๐Ÿ“’ ๐ŸŽŠ ๐Ÿ“š ๐Ÿ“– ๐Ÿ’™ ๐ŸŽ ๐ŸŽ‰

Happy Reading & Coding

๐Ÿ’ป ๐Ÿ““ ๐Ÿ“• ๐Ÿ“— ๐Ÿ“˜ ๐Ÿ“™ ๐Ÿ“” ๐Ÿ“’ ๐Ÿ“š ๐Ÿ“– ๐Ÿ’™ ๐Ÿ’œ ๐Ÿ’“ ๐Ÿ’— ๐Ÿ’– ๐Ÿ’˜ ๐Ÿ’ ๐ŸŽ ๐ŸŽŠ ๐ŸŽ‰

Top comments (10)

Collapse
 
abstract23 profile image
Arumita Das

Thank you .. its really great!! keep on posting.

Collapse
 
alucardu profile image
Peter Boomsma

Thank you for the content, but I'm running into an issue regarding Docker and Prisma. I've also posted the question here > stackoverflow.com/questions/689220...

I'm getting a authentication error when I run npx prisma migrate dev --name "init":

Error: P1000: Authentication failed against database server at localhost, the provided database credentials for db_user are not valid.

I've used your configuration and I'm running Windows. docker ps shows the server is running and Prisma is using the .env file. Any suggestions?

Collapse
 
alucardu profile image
Peter Boomsma

I resolved my issue. I was running a local instance of postgres on my Windows system as well. This was conflicting with the postgres instance in Docker. I removed postgres from Windows and everything is working.

Collapse
 
noleykuz profile image
Noleykuz

nice work Boss

Collapse
 
ebyjoan profile image
EbereJoan

Thank you sir for this wonderful piece.

Collapse
 
originalrexford profile image
Dev Rex

Good job

Collapse
 
nicholaschibueze profile image
Nicholas Chibueze Michael

thank you for the content it working

Collapse
 
nicholaschibueze profile image
Nicholas Chibueze Michael

thank you very much sir

Collapse
 
charlesceejay5 profile image
Charles Cee Jay

I encountered this error while running the node src/server.js file

Collapse
 
nditah profile image
Nditah

Please mention the error.