6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Deno+HonoでWebサーバを立てる ~DenoKVを添えて

Last updated at Posted at 2023-11-01

はじめに

先日、Deno Festをオンラインで聞いて面白いセッションが多かったので、DenoやHono、DenoKVなどを触ってみたくなりました。
簡単にAPIやユニットテストを作成・CIを整備して所感を書きます。DenoもHonoも初心者なので認識が誤っている箇所が含まれる可能性があります。その点ご容赦ください。

作ったもの

Denoについて

公式の説明によると

Deno (/ˈdiːnoʊ/, pronounced dee-no) is a JavaScript, TypeScript, and WebAssembly runtime with secure defaults and a great developer experience. It's built on V8, Rust, and Tokio.

つまり、Javascript・TypeScript・WebAssemblyのランタイムです。

Deno Festの話を聞いている限り、サーバサイド JavaScriptランタイムはNode以外にも、Deno/Bunなどが覇権を巡って争っている戦国時代のようです。

Denoの特徴

たくさんあるようですが、公式の説明によると

TypeScriptの組み込みサポート

Deno has built-in support for TypeScript as well.

JavaScriptへのトランスパイルが要りません。

デフォルトのセキュリティ

A major feature of Deno is runtime security by default, meaning that you as the developer must explicitly allow your code to access potentially sensitive APIs like file system access, network connectivity, and access to environment variables.

ファイルやネットワークへのアクセスに対して明示的に許可しないといけません。

URLからのライブラリの読み込み

Deno supports loading and executing code from URLs, much as you would using a <script> tag in the browser. In Deno 1.x, the standard library and most third-party modules are distributed on HTTPS URLs.

以下のようにURL指定でライブラリを読み込むことができます。

import { assertEquals } from "https://deno.land/std@0.204.0/assert/mod.ts";

組み込みテストランナー

Deno has a built-in test runner that you can use for testing JavaScript or TypeScript code.

Nodeにおけるjestなどのように、別でテストランナーを見繕う必要がありません。

などなどがあります。

また、npmもサポートされています。

Honoについて

公式によると

Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Vercel, Netlify, Lagon, AWS Lambda, Lambda@Edge, and Node.js.

どこでも動くめっちゃ早くてコンパクトなWebフレームワークとのことです。特にWeb標準に従って実装していることを売りにしています(Web標準に従っている実装ているからどのランタイムでも動く)。

Thanks to using only Web Standard APIs, we could make it work on Deno and Bun. "No Express for Bun?" we could answer, "No, but there is Hono" though Express works on Bun now.

使い方も簡単でexpressなどを触ったことがあればすぐに使用イメージが付くと思います。

また、今回は省いていますが、JSXサポートも進んでいるようです(Reactではないのでクライアントサイドのことはやらない)。

Deno KVについて

Deno組み込みのキーバリューストアです。現在(2023/11/01時点)Betaです。
APIもわかりやすいです。キーに配列で様々な値を渡せるのが特徴で、TanStack Queryを彷彿とさせます。簡易なAPIでCRUD操作が提供されています。

いざ実践

Deno環境構築

公式に従いDenoランタイムのインストールを行います。

curl -fsSL https://deno.land/x/install/install.sh | sh

パスを通すように表示されるのでパスを通します。

最後にパスが通っていることを確認します。

deno --version

image.png

Honoプロジェクトの作成

Deno向けの紹介ページがあるのでそちらの通り進めます。

deno run -A npm:create-hono my-app
cd my-app

プロジェクト設定

vscodeを前提に進めます。

vscodeのdeno用の拡張機能(denoland.vscode-deno)をインストールします。
image.png

.vscode/settings.jsonの設定をいじります。lint/formatを設定します。

.vscode/settings.json
{
  "deno.enablePaths": [
    "./"
  ],
  "deno.enable": true,
  "editor.inlayHints.enabled": "off",
  "deno.lint": true,
  "editor.formatOnSave": true,
  "[typescript]": {
    "editor.defaultFormatter": "denoland.vscode-deno"
  }
}

deno.jsonを作ります。今回は以下のように定義します。

deno.json
{
  // package.jsonのscriptsみたいなもの
  // ファイルアクセスやネットへのコネクションを許可したり、Deno KVを使うために--unstableフラグを渡しています。
  "tasks": {
    "dev": "deno run -A --unstable hello.ts",
    "test": "deno test -A --unstable"
  },
  // lockfileを作るかどうか
  "lock": false,
  // import specifiers
  "imports": {
    "hono": "https://deno.land/x/hono@v3.9.0/mod.ts",
    "ulid": "https://deno.land/x/ulid@v0.3.0/mod.ts",
    "assert": "https://deno.land/std@0.204.0/assert/mod.ts"
  }
}

CRUD用のメソッドを実装する

import { monotonicFactory } from "ulid";

const kv = await Deno.openKv("kv.sqlite");

type User = {
  name: string;
  age: number;
};

const findAllUsers = async () => {
  const entries = kv.list<User>({
    prefix: ["users", "id"],
  });
  let res: Array<User & { id: string }> = [];
  for await (const entry of entries) {
    res = [...res, { ...entry.value, id: entry.key[2] as string }];
  }
  return res;
};

const findUserById = async (id: string): Promise<User | null> => {
  const { value } = await kv.get<User>(["users", "id", id]);
  return value;
};

server実装

honoはexpress likeに実装することができます。

hello.ts
import { Hono } from "hono";

const app = new Hono();

app.get(
  "/users",
  async (c) => {
    const res = await findAllUsers();
    return c.json(res);
  },
).get("/users/:id", async (c) => {
  const id = c.req.param("id");
  const value = await findUserById(id);
  return value ? c.json({ ...value, id }) : c.json(notFound, 404);
});

Deno.serve(app.fetch);

export default app;

実行

deno task dev

image.png

テストを書く

Denoはテストランナーが内蔵されています。公式の例に従って実装します。

hello.test.ts
import app from "./hello.ts";
import { assert, assertEquals, assertInstanceOf } from "assert";

type User = { id: string; name: string; age: number };

Deno.test("GET /users", async () => {
  const res = await app.request("/users", { method: "GET" });
  assertEquals(res.status, 200);
  const json = await res.json();
  assertInstanceOf(json, Array<User>);
});

テストを実行する

deno task test

image.png

CI整備する

特にプロジェクト設定固有の設定はないのでgithubに出てきたものをほぼそのまま採用。

.github/workflows/deno.yml
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# This workflow will install Deno then run `deno lint` and `deno test`.
# For more information see: https://github.com/denoland/setup-deno

name: Deno

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Setup repo
        uses: actions/checkout@v3

      - name: Setup Deno
        # uses: denoland/setup-deno@v1
        uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31  # v1.1.2
        with:
          deno-version: v1.x

      # Uncomment this step to verify the use of 'deno fmt' on each commit.
      # - name: Verify formatting
      #   run: deno fmt --check

      - name: Run linter
        run: deno lint

      - name: Run tests
        run: deno task test

所感

Denoはごちゃごちゃしてなくていい

Nodeを用いた開発あるあるの大量の設定ファイル(package.json/eslint/prettier/jest.config...)がなく、node_modulesがなくJavaScriptのトランスパイルも意識しないのでリポジトリがとてもスッキリしていて認知的な負荷が低いように感じました。特に初心者が参画する案件などで認知的な負荷が低いのは重要な気がします。ただし、この辺は実務で利用すると何かとツールが増えてくるのかもしれません。

Honoはコンパクトな要件であれば使い勝手がよさそう

フレームワークとしてのお作法や決め事が非常に少ない印象で、学習コストが低そうです。そのうえでWeb標準に則っているため汎用性が高そうという意味で好印象を受けてました(テストを書く際に直感的に書くことができました)。一方で、シンプルゆえに、複雑な業務要件などがあるアプリ開発では、結構大変になるケースもありそうな印象を受けました(そういうケースはそもそもHonoがターゲットにしていないと思いますし)。

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?