Implement GraphQL with Drizzle

Introduction

In the previous article, I guided you on how to use Drizzle to connect with Postgres. Now, we will continue using it to implement GraphQL.

alt text

Next, we need to combine it with the following tools:

drizzle-graphql

This is the official library developed by the Drizzle ORM team itself to automatically generate a GraphQL Schema (including full Queries and Mutations) from your Drizzle Schema.

GraphQL Yoga

  • Serves as an extremely lightweight and modern GraphQL Server Framework (replacing the older/heavier Apollo Server).
  • Functions:
    • Listens for HTTP connections from the client (for example at port 4000/graphql).
    • Receives GraphQL (Query/Mutation) queries sent via POST requests.
    • Executes handler functions (Resolvers) and returns JSON data to the client.
    • Provides a built-in GraphiQL interface on the browser for you to test queries.

Detail

  • In this article, I will guide you on how to implement a simple CRUD GraphQL system. You only need to define the Schema and connect to Postgres.
  • You will not need to write much code and will still get a GraphQL system that satisfies the minimum requirements for use.

Create the file src/constant/key.ts to define the provider names:

export const DRIZZLE_DB = 'DRIZZLE_DB'
export const GRAPHQL_SCHEMA = 'GRAPHQL_SCHEMA'

Create the file src/drizzle-orm/schema/schema.ts, which simply includes products and carts:

import {
  bigserial,
  decimal,
  integer,
  pgTable,
  serial,
  text,
  timestamp,
  varchar,
} from 'drizzle-orm/pg-core'

export const products = pgTable('products', {
  id: bigserial('id', {mode: 'number'}).primaryKey(),
  name: varchar('name', {length: 255}).notNull(),
  description: text('description'),
  price: decimal('price', {precision: 10, scale: 2}).notNull(),
  views: integer('views').default(0),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
})

export const carts = pgTable('carts', {
  id: serial('id').primaryKey(),
  userId: integer('user_id').notNull().unique(),
  itemsJson: varchar('items_json', {length: 2000}).notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow(),
})

Create the file src/drizzle-orm/index.ts to create the Pool and Provider for Drizzle:

import {drizzle, type NodePgDatabase} from 'drizzle-orm/node-postgres'
import {Pool} from 'pg'
import {DRIZZLE_DB} from 'src/constant'
import * as schema from './schema/schema'

export type DrizzleDB = NodePgDatabase<typeof schema>

export const createPool = () => {
  return new Pool({connectionString: process.env.DATABASE_URL})
}

export const createDrizzle = () => {
  const pool = createPool()
  return drizzle(pool, {schema})
}

export const drizzleProvider = {
  provide: DRIZZLE_DB,
  useFactory: createDrizzle,
}

Create the file src/module/drizzle.module.ts to use drizzleProvider:

import {Global, Module} from '@nestjs/common'
import {buildSchema} from 'drizzle-graphql'
import {DRIZZLE_DB, GRAPHQL_SCHEMA} from 'src/constant'
import {drizzleProvider} from 'src/drizzle-orm'

@Global()
@Module({
  providers: [
    drizzleProvider,
    {
      provide: GRAPHQL_SCHEMA,
      inject: [DRIZZLE_DB],
      useFactory: db => {
        const {schema: graphQLSchema} = buildSchema(db)
        return graphQLSchema
      },
    },
  ],
  exports: [DRIZZLE_DB, GRAPHQL_SCHEMA],
})
export class DrizzleModule {}

Create the file src/middleware/graphql-yoga.middleware.ts:

import {Inject, Injectable, NestMiddleware} from '@nestjs/common'
import {Request, Response} from 'express'
import {type GraphQLSchema} from 'graphql'
import {createYoga, type YogaServerInstance} from 'graphql-yoga'
import {GRAPHQL_SCHEMA} from 'src/constant'

@Injectable()
export class GraphQLYogaMiddleware implements NestMiddleware {
  private yoga: YogaServerInstance<{}, {}>

  constructor(@Inject(GRAPHQL_SCHEMA) graphQLSchema: GraphQLSchema) {
    this.yoga = createYoga({
      schema: graphQLSchema,
      graphqlEndpoint: '/graphql',
    })
  }

  use(req: Request, res: Response) {
    this.yoga(req, res)
  }
}
  • This is the middleware used to process access to Yoga GraphiQL.
  • The graphqlEndpoint: '/graphql' part is the path that you can customize according to your needs.

Modify the file src/app.module.ts:

import {Module, type MiddlewareConsumer, type NestModule} from '@nestjs/common'
import {ConfigModule} from '@nestjs/config'
import {GraphQLYogaMiddleware} from './middleware/graphql-yoga.middleware'
import {DrizzleModule} from './module/drizzle.module'

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
    DrizzleModule,
  ],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(GraphQLYogaMiddleware).forRoutes('graphql')
  }
}

As a result, you can access Yoga GraphiQL using the URL localhost:5000/graphql. The Explorer section already includes the query and mutation information for the carts and products schemas.alt text

The Document section has full data type information for the fields.alt text

Try executing a query as follows, you just need to click on the fields you want to query:alt text

Create productalt text

Happy coding!

See more articles here.

Comments

Popular posts from this blog

All Practice Series

Understanding React Server Component

Kubernetes Deployment for Zero Downtime

Sitemap

Deploying a NodeJS Server on Google Kubernetes Engine

React Practice Series

Docker Practice Series

Setting up Kubernetes Dashboard with Kind

Helm for beginer - Deploy nginx to Google Kubernetes Engine

DevOps Practice Series