何をするか?
Deno Deploy を使うと、Web API を簡単にデプロイすることができます。 ここでは、よくある例として、サーバー側で JSON ファイルを読み込んで、その内容をレスポンスとして返す REST API を作ってみます。 ここでは、次のような関数やモジュールを使用します。
- Deno.readTextFile
- テキストファイルを読み込むために使用する Deno の標準 API です。
- x/oak モジュール
- HTTP サーバーを作るときに使えるミドルウェアフレームワークです。リクエストのパスに応じて、処理を簡単に振り分けることができます。Node の express と同じように使えます。
前提条件
Deno Deploy の基本的な使い方は下記ページを参考にしてください。
後述の記事では、デプロイ用の deployctl
コマンドを使用するので、上記ページに従って先にインストールしておいてください。
JSON ファイル
サーバー側で読み込む、サンプルの 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
関数で読み込むことができます。
// 読み込むデータの型情報
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 対応が必要です。
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());