DenoのOakでリクエスト情報を処理する方法

概要

DenoのOakでは、リクエストの処理はミドルウェア関数内で行います。
ミドルウェア関数の引数には、contextオブジェクトが渡されます。 このオブジェクトを使用して、リクエストに関連するデータの取得やレスポンスの生成などを行います。

ここでは、以下バージョンを使用した、Oakでリクエスト処理する方法を説明します。

Oak v8.0.0
Deno v1.16.2

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

リクエスト情報を取得する方法

リクエストに関する情報を取得するには、contextオブジェクトを使用します。 contextオブジェクトは、クライアントからのリクエストに関する情報を格納しています。Oakのミドルウェア関数内で使用され、リクエストヘッダー、パラメータ、ボディなどのデータにアクセスするために利用されます。

以下のサンプルコードは、Oakでcontextオブジェクトを理解するための例です。GETリクエストを受け取り、リクエストヘッダー、クエリパラメータにアクセスして、それらの値を含むレスポンスを返します。

request.ts

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

const router = new Router();
router.get('/', (context) => {
  // リクエストヘッダーの取得
  const headers = context.request.headers;

  // クエリパラメータの取得
  const queryParam = context.request.url.searchParams.get('param');

  const response = {
    headers: headers,
    queryParam: queryParam,
  };

  context.response.body = response;
});

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

app.listen({ port: 3000 });
console.log('Server is running on port 3000');

以下は、提供されたソースコードの説明です。

  1. oak モジュールから ApplicationRouter をインポートします。
import { Application, Router } from 'https://deno.land/x/oak/mod.ts';
  1. Router のインスタンスを作成します。
const router = new Router();
  1. ルートパス / に対して GET リクエストが送信された場合のミドルウェアを定義します。
router.get('/', (context) => {
  // リクエストヘッダーの取得
  const headers = context.request.headers;

  // クエリパラメータの取得
  const queryParam = context.request.url.searchParams.get('param');

  const response = {
    headers: headers,
    queryParam: queryParam,
  };

  // レスポンスボディを設定
  context.response.body = response;
});
  1. Application のインスタンスを作成します。
const app = new Application();
  1. Router をミドルウェアとして登録します。
app.use(router.routes());
app.use(router.allowedMethods());
  1. サーバーを指定したポート番号でリッスンします。
app.listen({ port: 3000 });
  1. コンソールにサーバーが起動した旨を出力します。
console.log('Server is running on port 3000');

以上がソースコードの概要です。このコードは、ルートパス / に対しての GET リクエストを受け取り、リクエストヘッダーとクエリパラメータを取得してレスポンスとして返します。サーバーはポート番号3000でリッスンし、起動後にメッセージをコンソールに出力します。

curl http://localhost:3000

リクエスト情報の検証する方法

この例では、/usersエンドポイントにPOSTリクエストが送信された際に、nameとageのフィールドが必須であり、ageは数値であることを検証します。

validate.ts

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

const router = new Router();

router.post("/users", async (context) => {
  const requestBody = await context.request.body().value;
  console.log(requestBody);
  if (
    !requestBody.name ||
    typeof requestBody.name !== "string" ||
    !requestBody.age ||
    typeof requestBody.age !== "number"
  ) {
    context.response.status = 400;
    context.response.body = { error: "Invalid request body" };
    return;
  }

  const { name, age } = requestBody;

  // バリデーションが成功した場合の処理
  context.response.body = { message: "User created successfully", name, age };
});

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

app.listen({ port: 3000 });
console.log("Server is running on port 3000");

以下は、提供されたソースコードの説明です。

  1. oak モジュールから ApplicationRouter をインポートします。
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
  1. Router のインスタンスを作成します。
const router = new Router();
  1. /users エンドポイントに対して POST リクエストが送信された場合のミドルウェアを定義します。
router.post("/users", async (context) => {
  // リクエストボディを取得
  const requestBody = await context.request.body().value;
  console.log(requestBody);
  
  // バリデーションチェック
  if (
    !requestBody.name ||
    typeof requestBody.name !== "string" ||
    !requestBody.age ||
    typeof requestBody.age !== "number"
  ) {
    // バリデーションエラーの場合はエラーレスポンスを返す
    context.response.status = 400;
    context.response.body = { error: "Invalid request body" };
    return;
  }

  const { name, age } = requestBody;

  // バリデーションが成功した場合の処理
  context.response.body = { message: "User created successfully", name, age };
});
  1. Application のインスタンスを作成します。
const app = new Application();
  1. Router をミドルウェアとして登録します。
app.use(router.routes());
app.use(router.allowedMethods());
  1. サーバーを指定したポート番号でリッスンします。
app.listen({ port: 3000 });
  1. コンソールにサーバーが起動した旨を出力します。
console.log("Server is running on port 3000");

以上がソースコードの概要です。このコードは、/users エンドポイントに対しての POST リクエストを受け取り、リクエストボディのバリデーションを行います。バリデーションが成功した場合は、レスポンスとして成功メッセージとユーザー情報を返します。バリデーションに失敗した場合は、エラーレスポンスを返します。サーバーはポート番号3000でリッスンし、起動後にメッセージをコンソールに出力します。

# 正常なリクエストのテスト
curl -X POST -H "Content-Type: application/json" -d '{"name":"John", "age": 25}' http://localhost:3000/users
# バリデーションエラーが発生するリクエストのテスト
curl -X POST -H "Content-Type: application/json" -d '{"name":"John"}' http://localhost:3000/users

まとめ

contextオブジェクトを使用することで、以下のことが可能になります:

  • リクエストヘッダーやクエリパラメータなどのリクエストデータにアクセスできます。
  • リクエストのパスパラメータやボディデータなど、リクエストの異なる部分のデータを取得できます。
  • 認証トークンやセッション情報など、リクエストに関連する認証や認可の情報を取得できます。
  • ミドルウェア関数を使用して、リクエストデータのバリデーションや変換を行うことができます。

contextオブジェクトを使用することで、リクエストのデータによる様々な操作を行うことができます。 contextオブジェクトには、多くのプロパティやメソッドがあり、高度なカスタマイズや制御が可能です。