まくろぐ
更新: / 作成:

何をするか?

Deno Deploy を使うと、Web API を簡単にデプロイすることができます。 ここでは、よくある例として、サーバー側で JSON ファイルを読み込んで、その内容をレスポンスとして返す REST API を作ってみます。 ここでは、次のような関数やモジュールを使用します。

  • Deno.readTextFile
    • テキストファイルを読み込むために使用する Deno の標準 API です。
  • x/oak モジュール
    • HTTP サーバーを作るときに使えるミドルウェアフレームワークです。リクエストのパスに応じて、処理を簡単に振り分けることができます。Node の express と同じように使えます。

前提条件

Deno Deploy の基本的な使い方は下記ページを参考にしてください。

後述の記事では、デプロイ用の deployctl コマンドを使用するので、上記ページに従って先にインストールしておいてください。

JSON ファイル

サーバー側で読み込む、サンプルの JSON ファイルを用意しておきます。

data/books.json
[
  {
    "id": "1",
    "title": "Title 1"
  },
  {
    "id": "2",
    "title": "Title 2"
  },
  {
    "id": "3",
    "title": "Title 3"
  }
]

3 冊の書籍データが格納されているという想定です。 実際のアプリケーションでは、RDB や mongoDB などのデータベースから情報取得することになると思います。

サーバーの実装

先に、data/books.json ファイルの情報を読み込んで返す getAllBooks 関数と getBook 関数を作成しておきます。 テキストファイルは、Deno.readTextFile 関数で読み込むことができます。

booksDb.ts
// 読み込むデータの型情報
type Book = {
  id: string;
  title: string;
};

// サンプルの JSON ファイルを読み込んでおく
const booksJson = await Deno.readTextFile("./data/books.json");
const books = JSON.parse(booksJson) as Book[];

/** 全ての書籍データを取得します */
export function getAllBooks() {
  return books;
}

/** 指定した ID の書籍データを取得します */
export function getBook(id: string | undefined): Book | undefined {
  return books.find((b) => b.id === id);
}

下記は、サーバーのエントリポイントとなるファイルで、oak の Router クラスを使って、次のようにリクエストを振り分けています。

  • /books … すべての書籍情報を返す。
  • /books/1 … 指定された ID (=1) に対応する書籍情報を返す。
import { Application, Router } from "https://deno.land/x/oak@v11.1.0/mod.ts";
import { getAllBooks, getBook } from "./booksDb.ts";

// Router を作成して、リクエストに応じて処理を振り分ける
const router = new Router();
router
  .use((ctx, next) => {
    // レスポンスのデフォルトの content-type を application/json にする
    ctx.response.type = "json";
    next();
  })
  .get("/books", (ctx) => {
    ctx.response.body = getAllBooks();
  })
  .get("/books/:id", (ctx) => {
    const book = getBook(ctx?.params?.id);
    ctx.response.body = book ?? { error: "Not Found" };
  });

// Create Application and register middlewares
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

// Start the server
await app.listen({ port: 8000 });

ローカルでのテストとデプロイ

サーバーの実装が終わったら、deno run でローカル実行して動作確認します。 ネットワークアクセスと、ファイルアクセスがあるので、--allow-net--allow-read を指定して起動する必要があります(面倒であれば -A であらゆるアクセスを許可しても OK)。

$ deno run --allow-net --allow-read main.ts

Web ブラウザや curl コマンドでアクセスして、正しく JSON データが返ってくるか確認します。

$ curl localhost:8000/books
[{"id":"1","title":"Title 1"},{"id":"2","title":"Title 2"},{"id":"3","title":"Title 3"}]

$ curl localhost:8000/books/1
{"id":"1","title":"Title 1"}

うまく動いているようなので、deployctl deploy コマンドで、Deno Deploy にデプロイします。

$ deployctl deploy --project your-project main.ts

デプロイ時に、カレントディレクトリにある data/books.json ファイルも同時に転送してくれるので、Deno Deploy サービス上でも正しく JSON ファイルを読み込むことができます。 デプロイが完了したら、発行された URL でアクセスしてみます。

$ curl https://your-project-a93nne0yv79j.deno.dev/books
[{"id":"1","title":"Title 1"},{"id":"2","title":"Title 2"},{"id":"3","title":"Title 3"}]

$ curl https://your-project-a93nne0yv79j.deno.dev/books/1
{"id":"1","title":"Title 1"}

バッチシ動きました! ٩(๑❛ᴗ❛๑)۶ わーぃ

CORS 対応

クライアントサイド JavaScript から REST API を呼び出す場合は、クロスドメインでの呼び出しを許可するための CORS 対応が必要です。

CORS エラーの例
Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin.

Deno の cors モジュール をインポートして、oak のミドルウェアとして設定すれば、ブラウザ上の JavaScript からアクセスできるようになります。

import { oakCors } from "https://deno.land/x/cors@v1.2.2/mod.ts";

const app = new Application();
app.use(oakCors()); // Enable CORS for All Routes
app.use(router.routes());

関連記事

まくろぐ
サイトマップまくへのメッセージ