在过去的几个月中,我几乎每天都在使用Deno,并且这个JavaScript运行时给我留下了深刻的印象。由于这个原因,我决定与您分享创建REST API的过程。到本文结束时,我们将将项目编译成具有较高可移植性的独立可执行文件。
介绍
在本文中,我们将创建一个REST API,在该API中我们执行著名的CRUD,以便每个人都有可能在本地进行测试,将使用的数据库是SQLite。
为您提供更多上下文,在本文中,我们将使用以下技术:
在开始本文之前,我建议您安装了Deno,并且使用节点有简短的经验。
设置项目
要开始,请导航到您选择的目录并运行以下命令:
deno init .
上面的命令有望在工作区中创建一组文件,因此,我们初始化了一个DENO项目,并将对deno.jsonc
文件进行一些更改。
首先定义我们将使用任务Runner deno task
:
运行的一些命令
{
"tasks": {
"dev": "deno run --watch main.ts",
"build": "deno compile main.ts"
}
}
接下来,让我们定义一些需要导入项目中的依赖项:
{
// ...
"imports": {
"hono": "https://deno.land/x/hono@v3.2.6/mod.ts",
"hono/middleware": "https://deno.land/x/hono@v3.2.6/middleware.ts",
"server": "https://deno.land/std@0.192.0/http/server.ts",
"denodb": "https://deno.land/x/denodb@v1.0.40/mod.ts",
"zod": "https://deno.land/x/zod@v3.21.4/mod.ts"
}
}
有了deno.jsonc
的最后一次更改,我们可以将项目配置作为完成,但是,如果您有兴趣了解有关该主题并扩展项目配置的更多信息,则可以看一下here。
,但是现在是时候让您的手弄脏了!
创建数据库模式和客户端
下一步将是创建项目中存在的实体,在这种情况下,我们只有一个,这将是Book
,但是除了实体,我们还将需要一个架构验证。
// @/db/models/book.ts
import { DataTypes, Model } from "denodb";
import { z } from "zod";
export class Book extends Model {
static table = "books";
static timestamps = true;
static fields = {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: DataTypes.STRING,
allowNull: false,
length: 25,
},
description: {
type: DataTypes.STRING,
allowNull: false,
length: 100,
},
isAvailable: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
};
static defaults = {
isAvailable: true,
};
}
export const bookSchema = z.object({
title: z.string(),
description: z.string(),
isAvailable: z.boolean(),
});
使用创建的实体,现在我们需要创建与数据库的连接,然后随后同步它。为此,首先,我们需要导入我们刚刚创建的Book
实体,然后我们将创建数据库的连接器和客户端实例,因此,我们将与数据库同步。
// @/db/connect.ts
import { Database, SQLite3Connector } from "denodb";
import { Book } from "./models/book.ts";
const connector = new SQLite3Connector({
filepath: "./dev.sqlite",
});
export const db = new Database(connector);
db.link([Book]);
这样,我们已经创建了数据库的架构和客户端,我们可以继续进行下一步。
定义路线
考虑到最后一点创建的内容,我们现在可以继续定义API路由。首先,我们需要导入Hono,以创建路由器,我们需要导入Book
实体和bookSchema
架构。
// @/router/book.ts
import { Hono } from "hono";
import { Book, bookSchema } from "../db/models/book.ts";
const book = new Hono();
// routes come here...
export { book };
完成此操作,我们现在可以定义第一条路线,其中我们将在数据库中存储所有书籍。
book.get("/book", async (c) => {
const list = await Book.all();
return c.json({ list }, 200);
});
在下一个路线中,在端点,我们将定义id
查询参数,以获取特定的书籍,以考虑其唯一标识符。
book.get("/book/:id", async (c) => {
const { id } = c.req.param();
const book = await Book.where("id", id).first();
return c.json(book, 200);
});
目前,我们有两条路线定义,另一条可以获取所有书籍,另一本可以获取特定书籍。但是当前数据库是空的,我们需要创建一条负责将新书插入数据库的路由。
使用此路线,您必须在请求正文中使用本书的数据定义JSON,以便可以插入它并确保我们插入预期的数据,我们将使用bookSchema
。
book.post("/book", async (c) => {
const body = await c.req.json();
const val = bookSchema.safeParse(body);
if (!val.success) return c.text("Invalid!", 500);
await Book.create({ ...val.data });
return c.body("Created", 201);
});
之后,由于我们设法创建了一本新书,因此我们还必须能够对其进行更新。为此,我们需要在路线中定义id
查询参数,以便我们知道要更新的书,然后在请求的正文中,预计数据将如预期的。
book.put("/book/:id", async (c) => {
const { id } = c.req.param();
const body = await c.req.json();
const val = bookSchema.safeParse(body);
if (!val.success) return c.text("Invalid!", 500);
await Book.where("id", id).update({ ...val.data });
return c.body("Updated", 200);
});
最后但并非最不重要的一点是,考虑到id
查询参数的值。
book.delete("/book/:id", async (c) => {
const { id } = c.req.param();
await Book.deleteById(id);
return c.body("Deleted", 200);
});
现在我们可以说我们已经注册了每条路线,这使我们可以进入下一个和最后一步。
设置中间件
在此步骤中,我们将为应用程序导入必要的中间Wares,不要忘记刚才创建的路由器,以及初始化数据库同步并提供API。这样:
// @/main.ts
import { Hono } from "hono";
import { cors, logger, prettyJSON } from "hono/middleware";
import { serve } from "server";
import { book } from "./router/book.ts";
import { db } from "./db/connect.ts";
const api = new Hono();
api.use("*", logger());
api.use("*", prettyJSON());
api.use("/api/*", cors());
api.route("/api", book);
api.notFound((c) => c.json({ message: "Not Found" }, 404));
await db.sync();
serve(api.fetch);
要启动该过程,只需运行以下命令:
deno task dev
要构建项目,只需运行以下命令:
deno task build
结论
我希望您能发现这篇文章有帮助,无论您是在现有项目中使用信息还是只是尝试一下。
如果您在文章中注意到任何错误,请告诉我。而且,如果您想查看本文的源代码,则可以在下面链接的github存储库上找到它。