使用Deno和Hono.js建立REST API:逐步指南
#javascript #网络开发人员 #教程 #deno

在过去的几个月中,我几乎每天都在使用Deno,并且这个JavaScript运行时给我留下了深刻的印象。由于这个原因,我决定与您分享创建REST API的过程。到本文结束时,我们将将项目编译成具有较高可移植性的独立可执行文件。

介绍

在本文中,我们将创建一个REST API,在该API中我们执行著名的CRUD,以便每个人都有可能在本地进行测试,将使用的数据库是SQLite。

为您提供更多上下文,在本文中,我们将使用以下技术:

  • hono - web framework
  • denodb -对象关联映射器(ORM)
  • zod-架构验证

在开始本文之前,我建议您安装了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存储库上找到它。

Github Repo