😍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?
}
Previous[Fullstack] Xây dựng forum bằng GraphQL, React, Apollo và Prisma - Part 4 (Backend - Connect to DataNextSetting Up Prisma with MySQL: A Step-by-Step Guid
Last updated