DenoのOakでルーティング処理を作成する方法

概要

Oakは、簡単にルーティングを定義できる機能を提供しています。
ルーティングは、HTTPリクエストを処理するためのエンドポイントを指定することで定義されます。

以下では、ルーティングの概念、ルートの定義、ルートハンドラの作成、ルーティングパラメータの処理、およびルートのオプションについて詳しく説明します。

ここでは、以下バージョンを使用した、ルーティング方法を説明します。

Deno v1.18.0
Oak v9.0.0

また、今回作成するコードは全て、以下に掲載しています。 https://github.com/wiblok/Deno-Oak

ルーティングの概念

ルーティングは、クライアントからのリクエストが特定のエンドポイントに到達した際に、Oakアプリケーションがどのように処理するかを定義します。

ルーティングは、HTTPメソッド(GET、POST、PUT、DELETEなど)とパス(URL)の組み合わせで定義されます。

ルーティングの定義方法

ルーティング使用する方法は以下の通りです。

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();
router.<HTTPメソッド>('<パス>', (context) => {
  // ルートの処理
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

  • HTTPメソッド: HTTPリクエストのメソッドを指定します(例: get、post、put、deleteなど)。
  • パス: クライアントからのリクエストがマッチするURLパスを指定します。

以下見出しからは、コードを記述します。

ルーティングオブジェクトを使用する方法

app.ts

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();

router.get("/hello", (context) => {
  context.response.body = "Hello, Oak!";
});

router.post("/users", async (context) => {
 

 const user = await context.request.body().value;
  // ユーザーの作成処理など...
  context.response.body = { id: 1, name: user.name };
});

router.put("/users/:id", async (context) => {
  if (context.params && context.params.id && context.request.hasBody) {
    const userId = context.params.id;
    const user = await context.request.body().value;
    // ユーザーの更新処理など...
    context.response.body = { id: userId, name: user.name };
  }
});

router.delete("/users/:id", (context) => {
  if (context.params && context.params.id) {
    const userId = context.params.id;
    // ユーザーの削除処理など...
    context.response.body = { message: `User ${userId} has been deleted.` };
  }
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 3000 });
console.log("サーバーがポート3000で起動しました");

このコードでは、Oakを使用して異なるHTTPメソッドに対する複数のパスのハンドラーを定義し、それらをOakアプリケーションに登録しています。

各ハンドラーは、リクエストを受け取り、適切な処理を行った後にレスポンスを返します。

解説

  • Oakモジュールのインポートとアプリケーション、ルーターの作成
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
const router = new Router();

この部分で、DenoのOakモジュールを読み込み、新しいOakアプリケーションインスタンスとルーターインスタンスを作成しています。

  • GETリクエストハンドラー
router.get("/hello", (context) => {
  context.response.body = "Hello, Oak!";
});

これにより、サーバーは"/hello"へのGETリクエストに対して"Hello, Oak!“をレスポンスとして返します。

  • POSTリクエストハンドラー
router.post("/users", async (context) => {
  const user = await context.request.body().value;
  // ユーザーの作成処理など...
  context.response.body = { id: 1, name: user.name };
});

これにより、"/users"へのPOSTリクエストは新しいユーザーの作成を試み、成功するとユーザー情報をJSON形式で返します。

  • PUTリクエストハンドラー
router.put("/users/:id", async (context) => {
  if (context.params && context.params.id && context.request.hasBody) {
    const userId = context.params.id;
    const user = await context.request.body().value;
    // ユーザーの更新処理など...
    context.response.body = { id: userId, name: user.name };
  }
});

これにより、"/users/:id"へのPUTリクエストは指定されたIDのユーザーの更新を試み、成功すると更新されたユーザー情報をJSON形式で返します。

  • DELETEリクエストハンドラー
router.delete("/users/:id", (context) => {
  if (context.params && context.params.id) {
    const userId = context.params.id;
    // ユーザーの削除処理など...
    context.response.body = { message: `User ${userId} has been deleted.` };
  }
});

これにより、"/users/:id"へのDELETEリクエストは指定されたIDのユーザーの削除を試み、成功するとユーザーが削除されたことを伝えるメッセージをJSON形式で返します。

  • ルーターの適用とサーバーの起動
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 3000 });

この部分で、アプリケーションにルーターを適用し、サーバーがポート3000でリスンするように設定しています。サーバーが起起動すると、コンソールに"サーバーがポート3000で起動しました"と表示されます。

テスト

# GETリクエストのテスト
curl -X GET http://localhost:3000/hello
# POSTリクエストのテスト
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# PUTリクエストのテスト
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# DELETEリクエストのテスト
curl -X DELETE http://localhost:3000/users/1

ルートチェーンの使用方法

chain.ts

import { Application, Router } from "https://deno.land/x/oak/mod.ts";

const router = new Router();

router
  .get("/hello", (context) => {
    context.response.body = "Hello, Oak!";
  })
  .post("/users", async (context) => {
    const user = await context.request.body().value;
    // ユーザーの作成処理など...
    context.response.body = { id: 1, name: user.name };
  })
  .put("/users/:id", async (context) => {
    if (context.params && context.params.id && context.request.hasBody) {
      const userId = context.params.id;
      const user = await context.request.body().value;
      // ユーザーの更新処理など...
      context.response.body = { id: userId, name: user.name };
    }
  })
  .delete("/users/:id", (context) => {
    if (context.params && context.params.id) {
      const userId = context.params.id;
      // ユーザーの削除処理など...
      context.response.body = { message: `User ${userId} has been deleted.` };
    }
  });

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 3000 });

解説

  • Oakモジュールのインポートとアプリケーション、ルーターの作成
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
const router = new Router();

この部分で、DenoのOakモジュールを読み込み、新しいOakアプリケーションインスタンスとルーターインスタンスを作成しています。

  • ルート設定
router
  .get("/hello", (context) => {
    context.response.body = "Hello, Oak!";
  })
  .post("/users", async (context) => {
    const user = await context.request.body().value;
    // ユーザーの作成処理など...
    context.response.body = { id: 1, name: user.name };
  })
  .put("/users/:id", async (context) => {
    if (context.params && context.params.id && context.request.hasBody) {
      const userId = context.params.id;
      const user = await context.request.body().value;
      // ユーザーの更新処理など...
      context.response.body = { id: userId, name: user.name };
    }
  })
  .delete("/users/:id", (context) => {
    if (context.params && context.params.id) {
      const userId = context.params.id;
      // ユーザーの削除処理など...
      context.response.body = { message: `User ${userId} has been deleted.` };
    }
  });

各HTTPメソッドのルートが一つのチェーンにつながれています。各ルートは特定のURLパスとHTTPメソッドに反応します。"/hello"へのGETリクエスト、"/users"へのPOSTリクエスト、"/users/:id"へのPUTとDELETEリクエストをハンドリングします。

  • ルーターの適用とサーバーの起動
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port: 3000 });

この部分で、アプリケーションにルーターを適用し、サーバーがポート3000でリスンするように設定しています。サーバーが起動したら、“サーバーがポート3000で起動しました"というメッセージがコンソールに表示されます。

テスト

# GETリクエストのテスト
curl -X GET http://localhost:3000/hello
# POSTリクエストのテスト
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:3000/users
# PUTリクエストのテスト
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane Smith"}' http://localhost:3000/users/1
# DELETEリクエストのテスト
curl -X DELETE http://localhost:3000/users/1

上記のコードでは、各HTTPメソッド(GET, POST, PUT, DELETE)に対応するエンドポイントを定義しています。各エンドポイントはそれぞれ異なる処理を実行し、結果をクライアントに返します。具体的なユーザーの作成、更新、削除の処理はここでは省略していますが、通常はこれらの部分でデータベースとのインタラクションが行われます。

まとめ

この記事では、DenoのOakフレームワークを使用してルーティングを行う方法について解説しました。以下に、主なポイントをまとめます:

  • Routerオブジェクトの使用: OakではRouterオブジェクトを作成し、その中に各ルートとそのハンドラ関数を定義します。これにより、異なるHTTPメソッドとパスに対するレスポンスを柔軟に使用することができます。
  • ハンドラ関数の定義: 各ルートに対してハンドラ関数を定義します。ハンドラ関数はリクエストを受け取り、適切な処理を行った後にレスポンスを返します。この処理は通常、データの取得や更新などの操作を含みます。
  • ルートパラメータの利用: Oakでは、ルートパラメータを使用してURLから特定の値を取り出すことができます。これにより、同じパスでもパラメータによって異なる動作を行うことが可能になります。
  • Oakサーバーの起動: Oakサーバーは指定したポートでリッスンするように設定します。そして、定義したルートを適用し、サーバーを起動します。

Oakを使用することで、DenoでHTTPサーバーを簡単に作成し、ルーティングを効率的に管理することが可能です。各ルートのハンドラ関数を適切に設計することで、アプリケーションの振る舞いを細かくコントロールできます。