介绍
学习新技术的过程通常会感到乏味,尤其是在您尚未看到行动中的最初阶段。
本文将指导您完成集成这些惊人的技术的过程,并演示如何使用它们构建小型应用程序。
在本文过程中,我们将开发一个博客应用程序,以展示CRUD操作在实践中的工作方式,并具有基本功能,包括:
- 创建新帖子
- 检索所有帖子或特定帖子
- 修改发布内容
- 最终删除职位
- 我们将实现的另一个功能是每个帖子都包含类似的计数。
crud表示创建,阅读,更新和删除
如果您有兴趣查看代码,请查看GitHub存储库here
先决条件
在进行继续之前,熟悉以下工具很重要:
- node.js and express.js
- 打字稿
- Prisma
如果您需要简要概述Prisma,我的博客文章here可能是一个有用的资源。
让我们开始ð
打开终端,然后使用以下命令创建并导航到文件夹目录
mkdir prisma-typescript-blog && cd prisma-typescript-blog
接下来,使用纱线初始化项目
yarn init -y
然后,安装依赖项
yarn add -D @types/express @types/node prisma ts-node-dev typescript
yarn add express @prisma/client
最后,用Prisma Cli的init
命令设置Prisma:
npx prisma init --datasource-provider sqlite
这将使用您的Prisma架构文件创建一个新的Prisma目录,并将SQLITE配置为数据库。
设置Prisma模式
prisma/prisma.schema
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Post {
id Int @id @default(autoincrement())
title String
content String
likesCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
content String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
post Post @relation(fields: [postId], references: [id])
postId Int
}
在上面的模式中,我们定义了包括Post
和Comment
的博客模型3
post Post @relation(fields: [postId], references: [id])
这种代码线意味着Post
和Comment
模型之间存在一对多关系。一个帖子可以发表很多评论,每个评论仅与一个帖子相关联。 Comment
模型中的postId
字段用于引用Post
模型中的id
字段。
完成此操作后,更新您的package.json
以使其看起来像:
{
"name": "prisma-typescript-blog",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "ts-node-dev --respawn --transpile-only --exit-child src/server.ts",
"db:migrate": "npx prisma migrate dev --name user-entity --create-only && npx prisma generate",
"db:push": "npx prisma db push"
},
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": [
"es6",
"dom"
]
},
"devDependencies": {
"@types/express": "^4.17.17",
"prisma": "^4.11.0",
"ts-node-dev": "^2.0.0",
"typescript": "^4.9.5"
},
"dependencies": {
"@prisma/client": "^4.11.0",
"dotenv": "^16.0.3",
"express": "^4.18.2"
}
}
-
start
启动节点JS服务器 -
db:migrate
-生成迁移文件和Prisma客户端 -
db:push
-将Prisma模式推向数据库
移民
在这一点上,您有一个Prisma模型,但还没有数据库。打开您的终端并运行以下命令以创建SQLITE数据库和以模型为代表的帖子表。
yarn db:migrate
运行命令后,Prisma CLI将分析您的模式并在prisma/migrations
目录中生成迁移文件。
将Prisma模式推向数据库:
yarn db:push
将SQLite数据库与Prisma模式同步后,运行npx prisma studio
以打开浏览器中的Prisma GUI工具。 Prisma Studio允许您查看和突变数据库中存储的数据。
现在,您的浏览器应自动打开一个新标签,您将看到类似的东西:
项目结构ð§
编辑您的项目结构,看起来像下面的
`prisma` -|
`schema.prisma`
`src` -|
`controllers`
-|
`post.controller.ts`
`routes`
-|
`post.route.ts`
`server.ts`
.env
`tsconfig.json`
.env
DATABASE_URL="file:./dev.db"
用上面的摘要替换.env
文件中的任何内容
让我们继续前进有趣的部分ð
server.ts
import express, { Request, Response } from "express";
import { PrismaClient } from "@prisma/client";
import PostRouter from "./routes/blog.route";
export const prisma = new PrismaClient();
const app = express();
const port = 8080;
async function main() {
app.use(express.json());
// Register API routes
app.use("/api/v1/post", PostRouter);
// Catch unregistered routes
app.all("*", (req: Request, res: Response) => {
res.status(404).json({ error: `Route ${req.originalUrl} not found` });
});
app.listen(port, () => {
console.log(`Server is listening on port ${port}`);
});
}
main()
.then(async () => {
await prisma.$connect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
这里发生了很多事情,所以让我解释
-
prisma = new PrismaClient()
-创建Prisma客户端的新实例 -
express.json()
登记中间件以解析传入的请求主体,为json。 -
app.use("/api/v1/post", PostRouter);
使用PoststRouter模块登录API路由。 -
app.all("*",...
定义了一条接收路线,以处理未注册的路线并返回404错误响应。
调用main()
函数时,它启动Express Server并使用Prisma客户端连接到数据库。如果有任何错误,它将错误记录到控制台并与数据库断开连接。
该代码是使用node.js,express.js和prisma orm构建API服务器的起点。它演示了如何处理API路由,连接到数据库,然后启动用于来源请求的服务器。
路线
routes/post.route.ts
import express from "express";
import PostController from "../controllers/post.controller";
const router = express.Router();
router.post("/create", PostController.createBlogPost);
router.post("/createPostAndComments", PostController.createPostAndComments);
router.get("/getall", PostController.getBlogPosts);
router.get("/get/:id", PostController.getBlogPost);
router.put("/update/:id", PostController.updateBlogPost);
router.delete("/delete/:id", PostController.deleteBlogPost);
router.delete("/deleteall", PostController.deleteAllBlogPosts);
router.post("/like", PostController.likeBlogPost);
export default router;
除了/createPostAndComments
路线外,这些路线非常简单。每个路由都处理特定的HTTP方法(发布,获取,放置或删除)。路由映射到PostController
控制器中定义的方法,该方法处理每个路由的逻辑。
这些路由的
/:id
部分是一个代表可以在URL中传递的动态值的参数。id
参数是特定值的占位符,例如博客文章的唯一标识符。
createPostAndComments
将帮助我们展示一对一的关系,因为它在架构中定义了。
在Post
Prisma模型中,Post
和Comment
之间存在一对多关系,其中一个Post
可以具有许多Comments
,但是每个Comment
只能属于一个Post
。这种关系是使用Post
模型中的comments
字段在Prisma模式中建模的:
model Post {
id Int @id @default(autoincrement())
title String
content String
likesCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
comments Comment[]
}
您可以看到,comments
字段是Comment
对象的数组,它代表一对一的关系。
控制器
controllers/post.controller.ts
import { Request, Response } from "express";
import { prisma } from "../server";
const createBlogPost = async (req: Request, res: Response) => {
try {
const { title, content } = req.body;
const newBlogPost = await prisma.post.create({
data: {
title,
content,
},
});
res.status(200).json(newBlogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
const createPostAndComments = async (req: Request, res: Response) => {
try {
const { title, content, comments } = req.body;
const newBlogPost = await prisma.post.create({
data: {
title,
content,
comments: {
create: comments,
},
},
include: {
comments: true, // Include the comments in the response
}
});
res.status(200).json(newBlogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
const getBlogPosts = async (req: Request, res: Response) => {
try {
const blogPosts = await prisma.post.findMany();
res.status(200).json(blogPosts);
} catch (e) {
res.status(500).json({ error: e });
}
};
const getBlogPost = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const blogPost = await prisma.post.findUnique({
where: {
id: Number(id),
},
});
res.status(200).json(blogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
const updateBlogPost = async (req: Request, res: Response) => {
try {
const { id, title, content } = req.body;
const updatedBlogPost = await prisma.post.update({
where: {
id: Number(id),
},
data: {
title,
content,
},
});
res.status(200).json(updatedBlogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
const deleteBlogPost = async (req: Request, res: Response) => {
try {
const { id } = req.body;
const deletedBlogPost = await prisma.post.delete({
where: {
id: Number(id),
},
});
res.status(200).json(deletedBlogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
const deleteAllBlogPosts = async (req: Request, res: Response) => {
try {
const deletedBlogPosts = await prisma.post.deleteMany();
res.status(200).json(deletedBlogPosts);
} catch (e) {
res.status(500).json({ error: e });
}
};
const likeBlogPost = async (req: Request, res: Response) => {
try {
const { id } = req.body;
const likedBlogPost = await prisma.post.update({
where: {
id: Number(id),
},
data: {
likesCount: {
increment: 1,
},
},
});
res.status(200).json(likedBlogPost);
} catch (e) {
res.status(500).json({ error: e });
}
};
export default {
createBlogPost,
createPostAndComments,
getBlogPosts,
getBlogPost,
updateBlogPost,
deleteBlogPost,
deleteAllBlogPosts,
likeBlogPost,
};
这个控制器非常笨重,所以我将继续解释每个方法。
我们的方法列出如下
createBlogPost
createPostAndComments
getBlogPosts
getBlogPost
updateBlogPost
deleteBlogPost
deleteAllBlogPosts
likeBlogPost
createBlogPost
这是一种接受title
和content
的非常简单的方法。它首先会破坏req.body
对象的标题和内容值,即请求有效载荷。
此外,它使用create()
方法来创建数据库中的新博客文章。此方法返回承诺,这就是为什么正在等待关键字等待操作完成之前完成执行之前的原因。
当向
http://localhost:8080/api/v1/post/create
端点提出请求主体中包含的凭据时,createBlogPost
处理程序将被唤起创建新的博客文章。
Postman是我测试所有端点的首选工具,但请随时使用您喜欢的测试工具。
createPostAndComments
CreatePostandComments方法期望请求主体包括title
,content
和comments
阵列。然后,该方法使用Prisma提供的create()方法创建新的帖子对象,并在数据对象中包含comments
。
Comment
对象将包括content
字段,因为当Comment
与新的Post
关联时,postId
字段将由prisma自动设置。
最后,include
参数用于在响应中包含新创建的Post
的comments
。
这是有效载荷和响应看起来像
updateBlogPost
该方法首先使用对象破坏从请求主体中提取id
,title
和content
属性。
然后,它使用Prisma使用指定的id
更新博客文章。 update()
方法在post
模型上调用,传递了指定where
和data
子句的对象。 where
子句指定要更新的博客文章的唯一标识符,而data
子句指定了title
和content
属性的新值。
likeBlogPost
该方法首先从请求主体中提取id
属性。此id
代表要喜欢的博客文章的唯一标识符。
然后,它使用Prisma prisma.post.update()
来更新指定的博客文章。 update()
方法在post
模型上调用,传递了指定where
和data
子句的对象。 where
子句指定了要更新的博客文章的唯一标识符,而数据条款increments
likesCount
属性则使用增量关键字
这是行动
当向
http://localhost:8080/api/v1/post/like
端点提出请求时,将id
作为主体传递时,它会调用createBlogPost
处理程序,而likesCount
将被递增
所有其他方法都与涵盖的方法非常相似,因此我不会浏览它们
在所有这些步骤之后,请确保您的服务器仍在运行,如果不运行yarn start
以使其启动并运行。
综上所述
本文通过使用节点,TypeScript和Prisma创建博客API来演示如何应用您对这些惊人工具的知识。此外,教程涵盖了将API与SQLite数据库连接的过程。
祝贺您到达本文的结尾!如果您发现它有帮助,请考虑对其表示赞许,并在下面留下您的评论。
在下一个ðð
中见