😍Prisma Crud Full

https://www.prisma.io/docs/orm/prisma-client/queries/crud Or https://graphql.org/learn

Example 1

src\index.js

import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
  const device = await prisma.device.create({
    data: {
      name: "Alice 2",
      data: { key: "value 2" },
    },
  });
  console.log(device);
}
main()
  .catch(async (e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

.env

DATABASE_URL="mysql://root@localhost:3306/prisma"

package.json

{
  "name": "graph",
  "version": "1.0.0",
  "main": "src/index.js",
  "type": "module",
  "scripts": {
    "dev": "nodemon src/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@prisma/client": "^6.2.1",
    "dotenv": "^16.4.7",
    "express": "^4.21.2",
    "express-graphql": "^0.12.0",
    "fs": "^0.0.1-security",
    "graphql": "^16.10.0",
    "graphql-yoga": "^5.10.9",
    "lodash": "^4.17.21",
    "nodemon": "^3.1.9",
    "path": "^0.12.7"
  }
}

prisma\schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
  provider = "prisma-client-js"
}
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}
model Device {
  id   Int     @id @default(autoincrement())
  name String
  data Json
}

Example 2 Full back-end

Part 1. Create database example

package.json

{
  "dependencies": {
    "@prisma/client": "^6.2.1",
    "cors": "^2.8.5",
    "express": "^4.21.2"
  },
  "devDependencies": {
    "@types/cors": "^2.8.17",
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.5",
    "@types/typescript": "^2.0.0",
    "prisma": "^6.2.1",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  },
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  }
}

— npx tsc --init read file typescript

npx tsc --init

— npx prisma

npx prisma

— npx prisma init

npx prisma init

— prisma db push

prisma db push

prisma\seed.ts

import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient();
const userData: Prisma.UserCreateInput[] = [
  {
    name: 'Lionel 1',
    email: 'lionel1@prisma.io',
    posts: {
      create: [
        {
          title: 'Post Lionel 1',
          content: 'https://slack.prisma.io',
          published: true,
        },
      ],
    },
  },
  {
    name: 'Lionel 2',
    email: 'lionel2@prisma.io',
    posts: {
      create: [
        {
          title: 'Post Lionel 2.1',
          content: 'https://slack.prisma.io',
          published: true,
        },
        {
          title: 'Post LIonel 2.2',
          content: 'https://pris.ly/youtube',
        },
      ],
    },
  },
];
async function main() {
  console.log(`Start seeding ...`);
  for (const u of userData) {
    const user = await prisma.user.create({
      data: u,
    })
    console.log(`Created user with id: ${user.id}`)
  }
  console.log(`Seeding finished.`)
}
main()
  .catch((e) => {
    console.error(e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })

— yarn prisma db seed

yarn prisma db seed

Part 2 Back-end

— package.json add scripts

"scripts": {
    "dev": "ts-node src/index.ts"
},

— npx prisma db push --force-reset

Khi muốn reset lại dữ liệu

cập nhật lại prisma\schema.prisma trong quá trình phát triển

npx prisma db push --force-reset
generator client {
  provider = "prisma-client-js"
}
datasource db {
  provider = "sqlite"
  url      = "file:./dev.sqlite"
}
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  Post  Post[]
}
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  viewCount Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

— Read database

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Create Post

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: false,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Get Post

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
})
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Delete Post

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
})
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
})
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Update Post

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { 
      title,
      content,
      viewCount,
      published: true 
    },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Update Status Post

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { 
      title,
      content,
      viewCount,
      published: true 
    },
  })
  res.json(post)
});
app.put('/publish/:id', async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { published: true },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Create User

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { 
      title,
      content,
      viewCount,
      published: true 
    },
  })
  res.json(post)
});
app.put('/publish/:id', async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { published: true },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
});
// Part 4
app.post(`/user`, async (req, res) => {
  const result = await prisma.user.create({
    data: {
      ...req.body,
    },
  })
  res.json(result)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— Get Users

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: {
      title,
      content,
      viewCount,
      published: true
    },
  })
  res.json(post)
});
app.put('/publish/:id', async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { published: true },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
});
// Part 4
app.post(`/user`, async (req, res) => {
  const result = await prisma.user.create({
    data: {
      ...req.body,
    },
  })
  res.json(result)
});
app.get(`/users`, async (req, res) => {
  const result = await prisma.user.findMany()
  res.json(result)
});
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

— filterPosts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { 
      title,
      content,
      viewCount,
      published: true 
    },
  })
  res.json(post)
});
app.put('/publish/:id', async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { published: true },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
});
// Part 4
app.post(`/user`, async (req, res) => {
  const result = await prisma.user.create({
    data: {
      ...req.body,
    },
  })
  res.json(result)
});
// Part 5
app.get('/filterPosts', async (req, res) => {
  const { title } = req.body;
  const filteredPosts = await prisma.post.findMany({
    where: {
      OR: [
        {
          title: {
            contains: title,
          },
        }
      ],
    },
  })
  res.json(filteredPosts)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

Or

src\index.ts

// Part 1
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
import cors from 'cors';
import express from 'express';
const app = express();
app.use(express.json())
app.use(cors());
// Part 2
app.get('/feed', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: true },
    include: { author: true }
  })
  res.json(posts)
});
app.get('/drafts', async (req, res) => {
  const posts = await prisma.post.findMany({
    where: { published: false },
    include: { author: true }
  })
  res.json(posts)
});
app.get(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.findUnique({
    where: {
      id: Number(id),
    },
    include: { author: true }
  })
  res.json(post)
});
app.delete(`/post/:id`, async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.delete({
    where: {
      id: Number(id),
    },
  })
  res.json(post)
});
app.put('/post/:id', async (req, res) => {
  const { id } = req.params;
  const { title, content, viewCount } = req.body;
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: {
      title,
      content,
      viewCount,
      published: true
    },
  })
  res.json(post)
});
app.put('/publish/:id', async (req, res) => {
  const { id } = req.params
  const post = await prisma.post.update({
    where: { id: Number(id) },
    data: { published: true },
  })
  res.json(post)
});
// Part 3
app.post(`/post`, async (req, res) => {
  const { title, content, authorEmail } = req.body
  const result = await prisma.post.create({
    data: {
      title,
      content,
      published: true,
      author: { connect: { email: authorEmail } },
    },
  })
  res.json(result)
});
// Part 4
app.post(`/user`, async (req, res) => {
  const result = await prisma.user.create({
    data: {
      ...req.body,
    },
  })
  res.json(result)
});
// Part 5
app.get('/filterPosts', async (req, res) => {
  const { title: searchTitle, content: searchContent } = req.body;
  const filteredPosts = await prisma.post.findMany({
    where: {
      OR: [
        {
          title: {
            contains: searchTitle,
          },
        },
        {
          content: {
            contains: searchContent
          },
        }
      ],
    },
  })
  res.json(filteredPosts)
})
const server = app.listen(3001, () =>
  console.log(
    '🚀 Server ready at: http://localhost:3001',
  ),
);

Part 3 Front-end

package.json

{
  "name": "crudfront",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "15.1.4",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-markdown": "^9.0.3"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

pages/_app.tsx

import "@/styles/globals.css";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

pages/_document.tsx

import { Html, Head, Main, NextScript } from "next/document";
import Header from '@/components/Header';
export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Header />
        <div className="container px-2 m-auto">
          <Main />
          <NextScript />
        </div>
      </body>
    </Html>
  );
}

pages\create.tsx

import React, { useState } from 'react'
import Router from 'next/router'
const Draft: React.FC = () => {
  const [title, setTitle] = useState('')
  const [content, setContent] = useState('')
  const [authorEmail, setAuthorEmail] = useState('')
  const submitData = async (e: React.SyntheticEvent) => {
    e.preventDefault()
    try {
      const body = { title, content, authorEmail }
      await fetch(`http://localhost:3001/post`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })
      await Router.push('/drafts')
    } catch (error) {
      console.error(error)
    }
  }
  return (
    <div>
      <h1 className='text-xl mb-2'>Create Draft</h1>
      <form
        onSubmit={submitData}>
        <input
          autoFocus
          onChange={e => setTitle(e.target.value)}
          placeholder="Title"
          type="text"
          value={title}
          className='mb-5 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 rounded-md sm:text-sm focus:ring-1 invalid:border-pink-500 invalid:text-pink-600 focus:invalid:border-pink-500 focus:invalid:ring-pink-500'
        />
        <br />
        <input
          onChange={e => setAuthorEmail(e.target.value)}
          placeholder="Author (email address)"
          type="text"
          value={authorEmail}
          className='mb-5 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 rounded-md sm:text-sm focus:ring-1 invalid:border-pink-500 invalid:text-pink-600 focus:invalid:border-pink-500 focus:invalid:ring-pink-500'
        />
        <br />
        <textarea
          cols={50}
          onChange={e => setContent(e.target.value)}
          placeholder="Content"
          rows={8}
          value={content}
          className='mb-5 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 rounded-md sm:text-sm focus:ring-1 invalid:border-pink-500 invalid:text-pink-600 focus:invalid:border-pink-500 focus:invalid:ring-pink-500'
        />
        <br />
        <input
          disabled={!content || !title || !authorEmail}
          type="submit"
          value="Create"
          className='bg-red-500 hover:bg-red-700 px-5 py-2 text-sm leading-5 rounded-full font-semibold text-white'
        />
        <a className="back" href="#" onClick={() => Router.push('/')}>
          or Cancel
        </a>
      </form>
    </div>
  )
}
export default Draft

pages\drafts.tsx

import React from "react"
import { GetServerSideProps } from "next"
import Post, { PostProps } from "@/components/Post"
type Props = {
  drafts: PostProps[]
}
const Drafts: React.FC<Props> = (props) => {
  return (
    <div className="page">
      <h1 className='text-xl mb-2'>Drafts</h1>
      <main>
        {props.drafts.map((post) => (
          <div key={post.id} className="post">
            <Post post={post} />
          </div>
        ))}
      </main>
    </div>
  )
}
export const getServerSideProps: GetServerSideProps = async () => {
  const res = await fetch("http://localhost:3001/drafts")
  const drafts = await res.json()
  return {
    props: { drafts },
  }
}
export default Drafts

pages\index.tsx

import React from 'react'
import { GetServerSideProps } from 'next'
import Post, { PostProps } from '@/components/Post'
type Props = {
  feed: PostProps[]
}
const Blog: React.FC<Props> = props => {
  return (
    <div className="page">
      <h1 className='text-xl mb-2'>My Blog</h1>
      <main>
        {props.feed.map(post => (
          <div key={post.id} className="post shadow mb-4 p-2">
            <Post post={post} />
          </div>
        ))}
      </main>
    </div>
  )
}
export const getServerSideProps: GetServerSideProps = async () => {
  const res = await fetch('http://localhost:3001/feed')
  const feed = await res.json()
  return {
    props: { feed },
  }
}
export default Blog

pages\signup.tsx

import React, { useState } from 'react'
import Router from 'next/router'
const SignUp: React.FC = () => {
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const submitData = async (e: React.SyntheticEvent) => {
    e.preventDefault()
    try {
      const body = { name, email }
      await fetch(`http://localhost:3001/user`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })
      await Router.push('/')
    } catch (error) {
      console.error(error)
    }
  }
  return (
    <div className="page">
      <h1 className='text-xl mb-2'>Signup user</h1>
      <form
        onSubmit={submitData}
        >
        <input
          autoFocus
          onChange={e => setName(e.target.value)}
          placeholder="Name"
          type="text"
          value={name}
          className='mb-5 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 rounded-md sm:text-sm focus:ring-1 invalid:border-pink-500 invalid:text-pink-600 focus:invalid:border-pink-500 focus:invalid:ring-pink-500'
        />
        <br/>
        <input
          onChange={e => setEmail(e.target.value)}
          placeholder="Email address"
          type="text"
          value={email}
          className='mb-5 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 rounded-md sm:text-sm focus:ring-1 invalid:border-pink-500 invalid:text-pink-600 focus:invalid:border-pink-500 focus:invalid:ring-pink-500'
        />
        <br/>
        <input
          disabled={!name || !email}
          type="submit"
          value="Signup"
          className='bg-red-500 hover:bg-red-700 px-5 py-2 text-sm leading-5 rounded-full font-semibold text-white'
        />
        <a className="back" href="#" onClick={() => Router.push('/')}>
          or Cancel
        </a>
      </form>
    </div>
  )
}
export default SignUp

pages\p\[id].tsx

import React from 'react'
import { GetServerSideProps } from 'next'
import ReactMarkdown from 'react-markdown'
import Router from 'next/router'
import { PostProps } from '../../components/Post'
async function publish(id: number): Promise<void> {
  await fetch(`http://localhost:3001/publish/${id}`, {
    method: 'PUT',
  })
  await Router.push('/')
}
async function destroy(id: number): Promise<void> {
  await fetch(`http://localhost:3001/post/${id}`, {
    method: 'DELETE',
  })
  await Router.push('/')
}
const Post: React.FC<PostProps> = props => {
  let title = props.title
  if (!props.published) {
    title = `${title} (Draft)`
  }
  return (
    <div>
      <h1 className='text-xl mb-2'>Post Detail</h1>
      <h2>{title}</h2>
      <p>By {props?.author?.name || 'Unknown author'}</p>
      <ReactMarkdown>{props.content}</ReactMarkdown>
      {!props.published && (
        <button onClick={() => publish(props.id)}>
          Publish
        </button>
      )}
      <button className='bg-red-500 hover:bg-red-700 px-5 py-2 text-sm leading-5 rounded-full font-semibold text-white' onClick={() => destroy(props.id)}>
        Delete
      </button>
    </div>
  )
}
export const getServerSideProps: GetServerSideProps = async (context) => {
  const id = context?.params?.id
  const res = await fetch(`http://localhost:3001/post/${id}`)
  const data = await res.json()
  return { props: { ...data } }
}
export default Post

components\Header.tsx

'use client'
import React from 'react'
import Link from 'next/link'
const Header: React.FC = () => {
  return (
    <nav className='flex justify-between bg-black text-white py-4 px-2'>
      <div className="flex gap-2" >
        <Link href="/" className="bold hover:text-emerald-400">
          Blog
        </Link>
        <Link href="/drafts" className="bold hover:text-emerald-400">
          Drafts
        </Link>
      </div>
      <div className="flex gap-2">
        <Link href="/signup" className="bold hover:text-emerald-400">
          Signup
        </Link>
        <Link href="/create" className="bold hover:text-emerald-400">
          Create draft
        </Link>
      </div>
    </nav>
  )
}
export default Header

components\Post.tsx

import React from 'react'
import Router from 'next/router'
import ReactMarkdown from "react-markdown";
export type PostProps = {
  id: number;
  title: string;
  author: {
    name: string;
  }
  content: string;
  published: boolean;
}
const Post: React.FC<{ post: PostProps }> = ({ post }) => {
  const authorName = post.author ? post.author.name : 'Unknown author'
  return (
    <div onClick={() => Router.push('/p/[id]', `/p/${post.id}`)}>
      <h2>{post.title}</h2>
      <small>By {authorName}</small>
      <ReactMarkdown children={post.content} />
    </div>
  )
}
export default Post

Part 4 Connect mysql

.env

DATABASE_URL="mysql://root@localhost:3306/crudback"
prisma db push

prisma\schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
  provider = "prisma-client-js"
}
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts  Post[]
}
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  viewCount Int      @default(0)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  author      User?    @relation(fields: [authorId], references: [id])
  authorId    Int?
}

Last updated