Skip to content

A production-ready boilerplate for building scalable GraphQL APIs with NestJS, Prisma, and MySQL. Includes Docker setup, role-based access control, JWT authentication (access + refresh tokens), and initial data seeding. Follows clean and hexagonal architecture principles for maintainability

Notifications You must be signed in to change notification settings

DarinelEscobar/graphql-template-hexagonal-architecture

Repository files navigation

Nest Logo

GraphQL API Template with NestJS, Prisma, and MySQL

This project is a boilerplate to build a GraphQL API using NestJS and Prisma, connected to a MySQL database. It includes a Docker setup for the database and an example seed script for initial data population.


πŸ”₯ Features (Updated)

  • βœ… JWT Authentication (Access + Refresh Tokens)
  • βœ… Role-Based Access Control using @Roles decorator and RolesGuard
  • βœ… Create Account and Login mutations with secure password hashing (bcrypt)
  • βœ… Refresh Token Mutation
  • βœ… Public GraphQL Queries: users, user(id)
  • βœ… Protected Queries:
    • products: Requires CHEF role
    • productsByUser: Requires USER or CHEF role
  • βœ… Global Rate Limiting via Throttler (custom GqlThrottlerGuard)

Prerequisites


Folder Structure (Example)

graphql-api-template
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ .env
β”œβ”€β”€ package.json
β”œβ”€β”€ prisma
β”‚   β”œβ”€β”€ schema.prisma
β”‚   └── seed.ts
β”œβ”€β”€ src
β”‚   β”œβ”€β”€ app.module.ts
β”‚   β”œβ”€β”€ main.ts
β”‚   └── user
β”‚       β”œβ”€β”€ user.module.ts
β”‚       β”œβ”€β”€ user.resolver.ts
β”‚       β”œβ”€β”€ user.service.ts
β”‚       └── user.type.ts
β”œβ”€β”€ tsconfig.json
└── ...

Environment Variables

In the root directory, create a .env file with your database connection URL, for example:

DATABASE_URL="mysql://root:@localhost:3306/graphql-db"

Prisma Setup

1. Define the schema in prisma/schema.prisma

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

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

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  password  String
  rol       String   @default("USER")  
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  products  Product[]
}

model Product {
  id        Int      @id @default(autoincrement())
  name      String
  userId    Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  user      User     @relation(fields: [userId], references: [id])
}


2. Run Database Migration

npx prisma migrate dev --name init

3. Generate Prisma Client

npx prisma generate

4. Seed Initial Data

prisma/seed.ts

import { PrismaClient } from '@prisma/client'
import * as bcrypt from 'bcryptjs'

const prisma = new PrismaClient()

async function main() {
  const salt = await bcrypt.genSalt(10)

  const user = await prisma.user.create({
    data: {
      name: 'Juan PΓ©rez',
      email: 's@user.com',
      password: await bcrypt.hash('12', salt),
      rol: 'USER',
    },
  })

  const chef = await prisma.user.create({
    data: {
      name: 'MarΓ­a Cocina',
      email: 's@chef.com',
      password: await bcrypt.hash('12', salt),
      rol: 'CHEF',
    },
  })

  await prisma.product.createMany({
    data: [
      { name: 'Taco Supremo', userId: user.id },
      { name: 'Burrito Deluxe', userId: user.id },
      { name: 'Paella Gourmet', userId: chef.id },
      { name: 'Sopa Azteca', userId: chef.id },
    ],
  })
}

main()
  .catch((e) => {
    console.error(e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })

Run the seed:

npx ts-node prisma/seed.ts

Project Setup

npm install

Run the Project

# development
npm run start

# watch mode
npm run start:dev

# production
npm run start:prod

The app will be running at http://localhost:3000.


GraphQL Playground

Go to http://localhost:3000/graphql.


Example Auth Mutations

πŸš€ Create Account

mutation {
  createAccount(data: { name: "Juan", email: "juan@example.com", password: "1234" }) {
    accessToken
    userId
    rol
    refreshToken
  }
}

πŸ” Login

mutation {
  login(data: { email: "juan@example.com", password: "1234" }) {
    accessToken
    userId
    rol
    refreshToken
  }
}

πŸ”„ Refresh Token

mutation {
  refreshToken(refreshToken: "yourRefreshTokenHere") {
    accessToken
    userId
    rol
    refreshToken
  }
}

Role-based GraphQL Query Protection

Query Roles Required Description
users ❌ Public Get all users
user(id) ❌ Public Get user by ID
products βœ… CHEF only Get all products
productsByUser βœ… USER, CHEF Get products by user ID

⚠️ products and productsByUser require an Authorization header with a valid token. Don’t even try without it:

{
  "Authorization": "Bearer YOUR_ACCESS_TOKEN"
}

Run Tests

# unit tests
npm run test

# e2e tests
npm run test:e2e

# test coverage
npm run test:cov

Deployment

npm install -g @nestjs/mau
mau deploy

Final Notes

Make sure to customize the .env configuration and never commit sensitive credentials. For production, use secret management tools and containerize the API if needed alongside the DB.

About

A production-ready boilerplate for building scalable GraphQL APIs with NestJS, Prisma, and MySQL. Includes Docker setup, role-based access control, JWT authentication (access + refresh tokens), and initial data seeding. Follows clean and hexagonal architecture principles for maintainability

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published