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.
- β JWT Authentication (Access + Refresh Tokens)
- β
Role-Based Access Control using
@Roles
decorator andRolesGuard
- β Create Account and Login mutations with secure password hashing (bcrypt)
- β Refresh Token Mutation
- β
Public GraphQL Queries:
users
,user(id)
- β
Protected Queries:
products
: RequiresCHEF
roleproductsByUser
: RequiresUSER
orCHEF
role
- β
Global Rate Limiting via Throttler (custom
GqlThrottlerGuard
)
- Node.js (recommended LTS version, 16+)
- Nest CLI (optional, for quick scaffolding)
- Docker and Docker Compose (for the MySQL database)
- MySQL Workbench or any other DB GUI tool (optional)
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
βββ ...
In the root directory, create a .env
file with your database connection URL, for example:
DATABASE_URL="mysql://root:@localhost:3306/graphql-db"
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])
}
npx prisma migrate dev --name init
npx prisma generate
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
npm install
# development
npm run start
# watch mode
npm run start:dev
# production
npm run start:prod
The app will be running at http://localhost:3000
.
Go to http://localhost:3000/graphql
.
mutation {
createAccount(data: { name: "Juan", email: "juan@example.com", password: "1234" }) {
accessToken
userId
rol
refreshToken
}
}
mutation {
login(data: { email: "juan@example.com", password: "1234" }) {
accessToken
userId
rol
refreshToken
}
}
mutation {
refreshToken(refreshToken: "yourRefreshTokenHere") {
accessToken
userId
rol
refreshToken
}
}
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
andproductsByUser
require anAuthorization
header with a valid token. Donβt even try without it:
{
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
# unit tests
npm run test
# e2e tests
npm run test:e2e
# test coverage
npm run test:cov
npm install -g @nestjs/mau
mau deploy
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.