使用 Hono JS 和 Drizzle ORM 的快速 REST API

此简短摘要最适合用作配套文档,以支持有关 Hono JS 和 Drizzle ORM 入门的视频教程。

我们创建了一组 API 路由来支持操作用户对象,即 sqlite 数据库,我们使用 drizzle ORM 与数据库交互

  • Hono - 快速、轻量、基于 Web 标准构建。支持任何 JavaScript 运行时。
  • Drizzle ORM——您可以在 TypeScript 中定义和管理数据库模式,以类似 SQL 或关系的方式访问您的数据,并利用选择加入的工具来大幅提升您的开发人员体验。
  • 安装和设置

    运行命令来开始使用基本的 Hono 应用程序,我们将重点关注 nodejs 构建。

    npm create hono@latest

    您的终端输出应该类似于以下信息。

    aaronksaunders@Aarons-iMac LIVE % npm create hono@latest
    Need to install the following packages:
    create-hono@0.14.3
    Ok to proceed? (y) y
    
    > npx
    > create-hono
    
    create-hono version 0.14.3
    ? Target directory my-hono-1
    ? Which template do you want to use? nodejs
    ? Do you want to install project dependencies? yes
    ? Which package manager do you want to use? npm
    ✔ Cloning the template
    ✔ Installing project dependencies
    🎉 Copied project files
    Get started with: cd my-hono-1

    hono 服务器的最小代码在 `index.ts` 中

    import { serve } from "@hono/node-server";
    import { Hono } from "hono";
    
    const app = new Hono();
    
    app.get("/", (c) => {
      return c.text("Hello Hono!");
    });
    
    // set port
    const port = 3000;
    console.log(`Server is running on http://localhost:${port}`);
    
    // serve app
    serve({
      fetch: app.fetch,
      port,
    });

    现在测试构建,切换到目录并运行下面的命令。

    npm run dev

    服务器应该在“localhost:3000”上运行,如果您在网络浏览器中访问它,您应该会收到来自服务器的响应。

    Hello Hono!

    添加 Drizzle 和 SQLite

    有用的链接

  • https://orm.drizzle.team/docs/get-started/sqlite-new
  • https://orm.drizzle.team/docs/get-started-sqlite#better-sqlite3
  • 在终端中运行以下命令

    npm i drizzle-orm better-sqlite3 dotenv
    npm i -D drizzle-kit tsx
  • better-sqlite-3 是我们在应用程序中使用的 sqlite 版本 -dotenv 用于读取环境文件
  • drizzle-kit 是一组支持 drizzle orm 集成的实用程序
  • 创建 `.env` 文件

    DATABASE_URL=./db.sqlite

    创建一个 drizzle 目录,迁移文件生成后将存放在这里。

    创建 `/src/db/schema.ts` 并添加以下信息

    import { sql } from "drizzle-orm";
    import { int, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
    
    export const usersTable = sqliteTable(
      "users_table",
      {
        id: int().primaryKey({ autoIncrement: true }),
        name: text().notNull(),
        age: int().notNull(),
        email: text().notNull().unique(),
        createdAt: text()
          .notNull()
          .default(sql`CURRENT_TIMESTAMP`),
        updatedAt: text()
          .notNull()
          .default(sql`CURRENT_TIMESTAMP`),
      },
      (table) => [uniqueIndex("email_idx").on(table.email)]
    );
    
    export type User = typeof usersTable.$inferSelect;
    export type InsertUser = typeof usersTable.$inferInsert;

    我们正在创建一个表并导出一些类型,这些类型可以在与查询输出交互时或构造需要进行查询的对象时使用。

    创建`/src/db/index.ts`,用于管理drizzle orm创建的数据库实例。

    // src/db/index.ts
    import { drizzle } from "drizzle-orm/better-sqlite3";
    import Database from "better-sqlite3";
    import * as schema from "./schema.js";
    import "dotenv/config";
    
    const sqlite = new Database(process.env.DATABASE_URL ?? "sqlite.db");
    
    export const db = drizzle(sqlite, { schema });

    在项目根目录中创建`drizzle.config.ts`

    import "dotenv/config";
    import { defineConfig } from "drizzle-kit";
    
    export default defineConfig({
      out: "./drizzle",
      schema: "./src/db/schema.ts",
      dialect: "sqlite",
      dbCredentials: {
        url: process.env.DATABASE_URL!,
      },
    });

    将脚本添加到 `package.json` 以生成迁移并将其应用于数据库

    "db:generate": "drizzle-kit generate",
     "db:migrate": "drizzle-kit migrate"

    运行脚本来创建数据库并推送迁移,终端输出应该类似于下面的输出。

    aaronksaunders@Aarons-iMac my-hono-1 % npm run db:generate                    
    
    > db:generate
    > drizzle-kit generate
    
    No config path provided, using default 'drizzle.config.ts'
    Reading config file '/Users/aaronksaunders/dev/LIVE/my-hono-1/drizzle.config.ts'
    1 tables
    users_table 6 columns 2 indexes 0 fks
    
    [✓] Your SQL migration file ➜ drizzle/0000_wakeful_greymalkin.sql 🚀
    aaronksaunders@Aarons-iMac my-hono-1 % npm run db:migrate 
    
    > db:migrate
    > drizzle-kit migrate
    
    No config path provided, using default 'drizzle.config.ts'
    Reading config file '/Users/aaronksaunders/dev/LIVE/my-hono-1/drizzle.config.ts'
    [✓] migrations applied successfully!%                                                         
    aaronksaunders@Aarons-iMac my-hono-1 %

    使用 drizzle kit studio 将一些用户添加到数据库。

    npx drizzle-kit studio

    添加查询数据库中用户的路由

    import { db } from "./db/index.js";
    import { Hono } from "hono";
    import { usersTable } from "./db/schema.js";
    import { eq } from "drizzle-orm";
    const usersRoute = new Hono();
    
    // Get all users
    usersRoute.get("/", async (c) => {
      const allUsers = await db.query.usersTable.findMany();
      return c.json(allUsers);
    });
    
    // Get a user by id, be sure to note the conversion of
    // the id from string back to a number
    usersRoute.get("/:id", async (c) => {
      const { id } = c.req.param();
      const userResp = await db.query.usersTable.findFirst({
        where: eq(usersTable.id, Number(id)),
      });
      return c.json(userResp);
    });
    
    // Create a user
    usersRoute.post("/", async (c) => {
      const { name, email, age } = await c.req.json();
      const newUserResp = await db.insert(usersTable).values({ name, email, age });
      return c.json(newUserResp);
    });
    
    export default usersRoute;

    修改 `index.ts` 以包含新的路线集

    import { serve } from "@hono/node-server";
    import { Hono } from "hono";
    import usersRoute from "./users-route.js";
    
    const app = new Hono();
    
    app.get("/", (c) => {
      return c.text("Hello Hono!");
    });
    
    // Use the users routes
    app.route("/users", usersRoute);
    
    const port = 3000;
    console.log(`Server is running on http://localhost:${port}`);
    
    serve({
      fetch: app.fetch,
      port,
    });

    使用 postman 或 thunderbolt VSCode Extension 等工具测试 API

    源代码

  • https://github.com/aaronksaunders/hono-drizzle-node-app-1
  • 视频

  • https://www.youtube.com/watch?v=dWGsvnjcgCw