GraphQL Server with PostgreSQL, Apollo and Node.js

By Nathan Anderson on Mar 13, 2022
#api#apollo#graphql#node#postgresql

Overview

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need, makes it easier to evolve APIs over time, and enables powerful developer tools.

In this article, we'll set up a GraphQL server with Node.js and Express. We'll use the Prima ORM to define our data model, and Apollo to handle the GraphQL logic. Next, we'll create our schema (with GQL syntax), then switch to typescript and create the same schema code-first. We'll also setup the Prisma client and create our first resolver. Finally, we'll start the server and take it for a spin!

Creating the Project

First, let's create a new directory for our project and initialize it with npm:

mkdir graphql-server && cd graphql-server
npm init -y

Great, now we have a package.json file that we can use to manage our dependencies.

Install dependencies

We'll need to install several dependencies for our project. We can do this with the following command:

npm install apollo-server type-graphql reflect-metadata prisma graphql @types/graphql --save

Then our dev dependencies:

npm install typescript ts-node @types/node @types/graphql nodemon --save-dev

This will install all of the dependencies we need, including GraphQL, Apollo Server, graphql-tools, TypeGraphQL and prisma. We'll also save the @types/graphql package to our dependencies so that we can use it later.

Setting up Prisma

Prisma allows you to easily manage your GraphQL data and queries, making development easier and faster.

npm install prisma --save-dev
npx prisma init

This command will generate a new folder in your project root named "prisma" with a "schema.prisma" file inside of it. This schema file contains the Prisma schema with your database connection variable and schema models

We'll use this simple example for the schema.

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

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

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

model Movie {
  id        Int      @id @default(autoincrement())
  title     String   @unique
  director  String
  year      Int
  genres    String[]
  reviews   Review[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Review {
  id        Int       @id @default(autoincrement())
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt
  movie     Movie     @relation(fields: [movieId], references: [id])
  movieId   Int
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  reviews Review[]
}

You'll also need to make sure you have a .env file with the database connection string set up.

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

For a quick, free PostgresSQL instance. You can quickly get one for free on Heroku or Supabase or Render. Alternatively, you can always set up PostgreSQL with a one-click install on DigitalOcean, or simply use their managed service.

We'll create our first migration and then install the prisma client that be used to access our tables.

npx prisma migrate dev --name init
npm install @prisma/client

Setting up Apollo Server

Firstly, we will need to create a connection to our database using an instance of the Prisma client. We will later be able to pass this into the creation of our Apollo Server and use it inside our resolvers to retrieve data from the database.

Let's create a new file to define our context and create the Prisma client.

import { PrismaClient } from "@prisma/client";

export interface Context {
  prisma: PrismaClient;
}

const prisma = new PrismaClient();

export const context: Context = {
  prisma: prisma,
};

Now that we have our context defined, let's set up Apollo Server with a simple schema and query.

If you have downloaded the template, you should already have the server configuration in server.ts similar to the below

import { ApolloServer, gql } from "apollo-server";

const typeDefs = gql`
  # Comments in GraphQL strings (such as this one) start with the hash (#) symbol.

  # This "Book" type defines the queryable fields for every book in our data source.
  type Movies {
    title: String
    director: String
  }

  # The "Query" type is special: it lists all of the available queries that
  # clients can execute, along with the return type for each. In this
  # case, the "books" query returns an array of zero or more Books (defined above).
  type Query {
    movies: [Movies]
  }
`;

const resolvers = {
  Query: {
    movies: () => [
      {
        title: "The Shawshank Redemption",
        director: "Frank Darabont"
      },
      {
        title: "Jurassic Park",
        director: "Steven Spielberg"
      }
    ]
  }
};
const server = new ApolloServer({typeDefs,resolvers});

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

Queries

There are two ways to support writing queries and mutations. The traditional style, with the GQL syntax, and the Typescript style, courtesy of TypeGraphQL. In this article, we have set up simple queries using the typical Schema Definition Language (SDL) syntax. In a follow-up post we'll show how to take this to the next level and use Typescript to create resolvers and even automatically generate them for us!

Conclusion

In this tutorial, we've learned how to create a graphql server with Typescript, Prisma and Apollo. We've created a graphql schema for our database and written resolvers for our fields. We've also learned about Prisma and how to use it to turn our database into a graphql API.