Loading...
Loading...
mkdir api && cd api
npm init -y
npm install express prisma @prisma/client zod bcrypt jsonwebtoken
npm install -D typescript @types/node @types/express tsx nodemon// prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
password String
name String
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id Int @id @default(autoincrement())
title String
slug String @unique
content String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}npx prisma migrate dev --name init// src/routes/posts.ts
import { Router } from 'express'
import { PrismaClient } from '@prisma/client'
import { z } from 'zod'
import { authenticate } from '../middleware/auth'
const router = Router()
const prisma = new PrismaClient()
const createPostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(10),
published: z.boolean().optional(),
})
router.get('/', async (req, res) => {
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: { select: { name: true } } },
orderBy: { createdAt: 'desc' },
})
res.json(posts)
})
router.post('/', authenticate, async (req, res) => {
const body = createPostSchema.safeParse(req.body)
if (!body.success) return res.status(400).json(body.error)
const post = await prisma.post.create({
data: { ...body.data, authorId: req.user.id, slug: slugify(body.data.title) },
})
res.status(201).json(post)
})
export default router// src/middleware/auth.ts
import jwt from 'jsonwebtoken'
import type { Request, Response, NextFunction } from 'express'
export function authenticate(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace('Bearer ', '')
if (!token) return res.status(401).json({ message: 'Unauthorized' })
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number }
req.user = { id: payload.userId }
next()
} catch {
res.status(401).json({ message: 'Invalid token' })
}
}Node.js + Express + Prisma is one of the most productive stacks for building REST APIs. Prisma's type-safe queries eliminate a whole class of runtime errors, and Zod keeps your inputs clean.